我正在向页面添加html5拖放上传器。
将文件放到上载区域后,一切正常。
但是,如果我不小心将文件放在了上传区域之外,浏览器将加载本地文件,就像它是一个新页面一样。
如何防止这种行为?
谢谢!
我正在向页面添加html5拖放上传器。
将文件放到上载区域后,一切正常。
但是,如果我不小心将文件放在了上传区域之外,浏览器将加载本地文件,就像它是一个新页面一样。
如何防止这种行为?
谢谢!
Answers:
您可以将事件侦听器添加到调用preventDefault()
所有拖放事件的窗口。
例:
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,无论这些属性是否设置为new。
要仅允许对某些元素进行拖放,可以执行以下操作:
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);
默认情况下,阻止所有拖放操作可能不是您想要的。至少在某些浏览器中,可以检查拖动源是否是外部文件。我在StackOverflow答案中包含了一个检查拖动源是否是外部文件的功能。
修改Digital Plane的答案,您可以执行以下操作:
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);
注意:尽管OP并没有要求提供Angular解决方案,但我还是来这里寻找的。因此,这是分享我发现可行的解决方案(如果使用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);
在Mac上的Firefox上进行了测试。
我将一个类选择器用于多个上传区域,所以我的解决方案采用了这种不太纯净的形式
基于Axel Amthor的答案,并依赖于jQuery(别名为$)
_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);
});
},