ฉันกำลังเพิ่มตัวอัปโหลดลากและวาง html5 ในหน้าของฉัน
เมื่อไฟล์ถูกทิ้งลงในพื้นที่อัพโหลดทุกอย่างใช้งานได้ดี
อย่างไรก็ตามหากฉันบังเอิญวางไฟล์นอกพื้นที่อัพโหลดเบราว์เซอร์จะโหลดไฟล์ในเครื่องเสมือนว่าเป็นหน้าใหม่
ฉันจะป้องกันพฤติกรรมนี้ได้อย่างไร
ขอบคุณ!
ฉันกำลังเพิ่มตัวอัปโหลดลากและวาง html5 ในหน้าของฉัน
เมื่อไฟล์ถูกทิ้งลงในพื้นที่อัพโหลดทุกอย่างใช้งานได้ดี
อย่างไรก็ตามหากฉันบังเอิญวางไฟล์นอกพื้นที่อัพโหลดเบราว์เซอร์จะโหลดไฟล์ในเครื่องเสมือนว่าเป็นหน้าใหม่
ฉันจะป้องกันพฤติกรรมนี้ได้อย่างไร
ขอบคุณ!
คำตอบ:
คุณสามารถเพิ่ม listener เหตุการณ์ไปยังหน้าต่างที่เรียกpreventDefault()ใช้ dragover และ drop events ทั้งหมด
ตัวอย่าง:
window.addEventListener("dragover",function(e){
e = e || event;
e.preventDefault();
},false);
window.addEventListener("drop",function(e){
e = e || event;
e.preventDefault();
},false);
dragoverและdropตัวจัดการเพื่อป้องกันไม่ให้เบราว์เซอร์โหลดไฟล์ที่ถูกทิ้ง (Chrome ล่าสุด 2015/08/03) วิธีแก้ปัญหาทำงานบน FF ล่าสุดด้วย
<input type="file" />นี้ยังปิดการใช้งานไฟล์ลากบน มีความจำเป็นต้องตรวจสอบว่าe.targetเป็นไฟล์อินพุตและให้เหตุการณ์ดังกล่าวผ่าน
หลังจากเล่นซอไปรอบ ๆ ฉันพบว่านี่เป็นทางออกที่เสถียรที่สุด:
var dropzoneId = "dropzone";
window.addEventListener("dragenter", function(e) {
if (e.target.id != dropzoneId) {
e.preventDefault();
e.dataTransfer.effectAllowed = "none";
e.dataTransfer.dropEffect = "none";
}
}, false);
window.addEventListener("dragover", function(e) {
if (e.target.id != dropzoneId) {
e.preventDefault();
e.dataTransfer.effectAllowed = "none";
e.dataTransfer.dropEffect = "none";
}
});
window.addEventListener("drop", function(e) {
if (e.target.id != dropzoneId) {
e.preventDefault();
e.dataTransfer.effectAllowed = "none";
e.dataTransfer.dropEffect = "none";
}
});
<div id="dropzone">...</div>
การตั้งค่าทั้งสองeffectAllowและdropEffectไม่มีเงื่อนไขบนหน้าต่างทำให้ฉันปล่อยโซนไม่ยอมรับ dnd ใด ๆ อีกต่อไปไม่ว่าคุณสมบัติจะถูกตั้งค่าใหม่หรือไม่
สำหรับ jQuery คำตอบที่ถูกต้องคือ:
$(document).on({
dragover: function() {
return false;
},
drop: function() {
return false;
}
});
ที่นี่return falseจะทำงานเป็นและevent.preventDefault()event.stopPropagation()
ในการอนุญาตให้ลากและวางในองค์ประกอบบางอย่างเท่านั้นคุณสามารถทำสิ่งต่อไปนี้
window.addEventListener("dragover",function(e){
e = e || event;
console.log(e);
if (e.target.tagName != "INPUT") { // check which element is our target
e.preventDefault();
}
},false);
window.addEventListener("drop",function(e){
e = e || event;
console.log(e);
if (e.target.tagName != "INPUT") { // check which element is our target
e.preventDefault();
}
},false);
ลองนี้:
document.body.addEventListener('drop', function(e) {
e.preventDefault();
}, false);
การป้องกันการลากและวางทั้งหมดโดยค่าเริ่มต้นอาจไม่ใช่สิ่งที่คุณต้องการ เป็นไปได้ที่จะตรวจสอบว่าแหล่งที่มาของการลากเป็นไฟล์ภายนอกหรือไม่ในเบราว์เซอร์บางตัว ฉันได้รวมฟังก์ชันเพื่อตรวจสอบว่าแหล่งที่มาของการลากเป็นไฟล์ภายนอกในคำตอบของ StackOverflowนี้หรือไม่
การแก้ไขคำตอบของเครื่องบินดิจิทัลคุณสามารถทำสิ่งนี้:
function isDragSourceExternalFile() {
// Defined here:
// https://stackoverflow.com/a/32044172/395461
}
window.addEventListener("dragover",function(e){
e = e || event;
var IsFile = isDragSourceExternalFile(e.originalEvent.dataTransfer);
if (IsFile) e.preventDefault();
},false);
window.addEventListener("drop",function(e){
e = e || event;
var IsFile = isDragSourceExternalFile(e.originalEvent.dataTransfer);
if (IsFile) e.preventDefault();
},false);
e || event;คืออะไร อยู่ที่ไหนeventกำหนด? ไม่เป็นไร. ดูเหมือนว่าเป็นวัตถุระดับโลกใน IE? ฉันพบข้อความนี้"In Microsoft Visual Basic Scripting Edition (VBScript), you must access the event object through the window object." ที่นี่
หมายเหตุ:ถึงแม้ว่า OP ไม่ได้ขอวิธีการแก้ปัญหาเชิงมุม แต่ฉันมาที่นี่เพื่อค้นหา ดังนั้นนี่คือการแบ่งปันสิ่งที่ฉันพบว่าเป็นทางออกที่ทำงานได้ถ้าคุณใช้ Angular
จากประสบการณ์ของฉันปัญหานี้เกิดขึ้นก่อนเมื่อคุณเพิ่มฟังก์ชั่นการปล่อยไฟล์ลงในหน้า ดังนั้นความเห็นของฉันคือองค์ประกอบที่เพิ่มสิ่งนี้ควรรับผิดชอบในการป้องกันการตกนอกเขตหล่น
ในโซลูชันของฉันโซนดร็อปเป็นอินพุตที่มีคลาส แต่ตัวเลือกใด ๆ ที่ทำงานได้ชัดเจน
import { Component, HostListener } from '@angular/core';
//...
@Component({
template: `
<form>
<!-- ... -->
<input type="file" class="dropzone" />
</form>
`
})
export class MyComponentWithDropTarget {
//...
@HostListener('document:dragover', ['$event'])
@HostListener('drop', ['$event'])
onDragDropFileVerifyZone(event) {
if (event.target.matches('input.dropzone')) {
// In drop zone. I don't want listeners later in event-chain to meddle in here
event.stopPropagation();
} else {
// Outside of drop zone! Prevent default action, and do not show copy/move icon
event.preventDefault();
event.dataTransfer.effectAllowed = 'none';
event.dataTransfer.dropEffect = 'none';
}
}
}
ผู้ฟังจะถูกเพิ่ม / ลบโดยอัตโนมัติเมื่อมีการสร้าง / ทำลายส่วนประกอบและส่วนประกอบอื่น ๆ ที่ใช้กลยุทธ์เดียวกันในหน้าเดียวกันไม่รบกวนซึ่งกันและกันเนื่องจาก stopPropagation ()
หากต้องการสร้างวิธี "ตรวจสอบเป้าหมาย" ที่ระบุไว้ในคำตอบอื่น ๆ ต่อไปนี้เป็นวิธีทั่วไป / หน้าที่เพิ่มเติม:
function preventDefaultExcept(predicates) {
return function (e) {
var passEvery = predicates.every(function (predicate) { return predicate(e); })
if (!passEvery) {
e.preventDefault();
}
};
}
เรียกว่า:
function isDropzone(e) { return e.target.id === 'dropzone'; }
function isntParagraph(e) { return e.target.tagName !== 'p'; }
window.addEventListener(
'dragover',
preventDefaultExcept([isDropzone, isntParagraph])
);
window.addEventListener(
'drop',
preventDefaultExcept([isDropzone])
);
function preventDefaultExcept(...predicates){}บางอย่างที่นี่: และจากนั้นใช้มันเหมือนกันpreventDefaultExcept(isDropzone, isntParagraph)
ฉันมี HTML object( embed) ที่เติมความกว้างและความสูงของหน้า คำตอบโดย @ digital-plane ทำงานบนเว็บเพจปกติ แต่ไม่ใช่ถ้าผู้ใช้วางลงบนวัตถุฝังตัว ดังนั้นฉันต้องการโซลูชันที่แตกต่าง
หากเราเปลี่ยนไปใช้การใช้ช่วงการดักจับเหตุการณ์เราสามารถรับเหตุการณ์ก่อนที่วัตถุฝังตัวจะได้รับ (สังเกตเห็นtrueค่าเมื่อสิ้นสุดการเรียกฟังเหตุการณ์):
// document.body or window
document.body.addEventListener("dragover", function(e){
e = e || event;
e.preventDefault();
console.log("over true");
}, true);
document.body.addEventListener("drop", function(e){
e = e || event;
e.preventDefault();
console.log("drop true");
}, true);
การใช้รหัสต่อไปนี้ (ขึ้นอยู่กับคำตอบของ @ digital-plane) หน้าจะกลายเป็นเป้าหมายการลากมันจะป้องกันไม่ให้วัตถุฝังจากการดักจับเหตุการณ์แล้วโหลดภาพของเรา:
document.body.addEventListener("dragover", function(e){
e = e || event;
e.preventDefault();
console.log("over true");
}, true);
document.body.addEventListener("drop",function(e){
e = e || event;
e.preventDefault();
console.log("Drop true");
// begin loading image data to pass to our embed
var droppedFiles = e.dataTransfer.files;
var fileReaders = {};
var files = {};
var reader;
for (var i = 0; i < droppedFiles.length; i++) {
files[i] = droppedFiles[i]; // bc file is ref is overwritten
console.log("File: " + files[i].name + " " + files[i].size);
reader = new FileReader();
reader.file = files[i]; // bc loadend event has no file ref
reader.addEventListener("loadend", function (ev, loadedFile) {
var fileObject = {};
var currentReader = ev.target;
loadedFile = currentReader.file;
console.log("File loaded:" + loadedFile.name);
fileObject.dataURI = currentReader.result;
fileObject.name = loadedFile.name;
fileObject.type = loadedFile.type;
// call function on embed and pass file object
});
reader.readAsDataURL(files[i]);
}
}, true);
ทดสอบบน Firefox บน Mac
ฉันกำลังใช้ตัวเลือกคลาสสำหรับพื้นที่อัปโหลดหลายแห่งดังนั้นโซลูชันของฉันจึงใช้รูปแบบที่บริสุทธิ์น้อยกว่านี้
ตามคำตอบของ Axel Amthor โดยขึ้นอยู่กับ jQuery (aliased ถึง $)
_stopBrowserFromOpeningDragAndDropPDFFiles = function () {
_preventDND = function(e) {
if (!$(e.target).is($(_uploadBoxSelector))) {
e.preventDefault();
e.dataTransfer.effectAllowed = 'none';
e.dataTransfer.dropEffect = 'none';
}
};
window.addEventListener('dragenter', function (e) {
_preventDND(e);
}, false);
window.addEventListener('dragover', function (e) {
_preventDND(e);
});
window.addEventListener('drop', function (e) {
_preventDND(e);
});
},