我试图检测是否在dragover
或dragenter
事件中拖动了文件夹或文件。
在ondrop
事件中,有一个名为MouseEvent
的论据,其中有一个名为dataTransfer
的字段,其中列出了文件(.files
)或项目(.items
),具体取决于浏览器,我可以在Chrome和Firefox中读到它。然而,对于dragover
和dragenter
事件,那些领域(.files
和.items
)是空的。问题是我在拖动时需要这些信息,而不是丢弃。
注意:对于文件和文件夹,event.dataTransfer.types[i] === "Files"
是true
。
我发现the following answer部分适合我的问题:
当你可以调用
getData
时,WebKit,以及Chrome,是非常严格的限制。你不允许在dragstart
或dragover
内进行。我认为这是规范的错误。
但答案是从2012年开始,我无法找到有关该主题的实际更新信息,因此我正在寻找有关此问题的最新信息。
TL; DR你不能:(
如果你想知道为什么这个问题还没有得到一个可接受的答案,你可以阅读由OP和this meta question创建的my answer。
drag
/drop
in HTML5我在这个主题的许多文档中做了一些研究,并在各种浏览器上自己测试了,所以我决定总结一下我所知道的关于文件拖放的所有知识。
拖动文件时可以使用一些侦听器,例如:
dragenter
dragover
dragend
dragleave
鉴于这些是drag
事件,files
的event.dataTransfer
属性要么有length == 0
要么是空的(null
)。
想象一下,您可以在拖动事件中读取文件:即使用户不想将文件上传到您的站点,您也可以阅读所有内容。认真对待它是没有意义的。想象一下,您正在将文件从桌面拖到另一个文件夹,并且不小心将其拖动到网页中:现在网页会读取您的文件并将您的个人信息存储在其服务器上......这将是一个巨大的安全漏洞。
但是,您仍然可以通过迭代数组event.dataTransfer.types
来检测用户是否正在拖动文件(以及文件我也指文件夹,因为文件夹是文件)。您可以创建一个函数来检查拖动事件是否包含文件,然后在事件处理程序中调用它。
例:
function containsFiles(event) {
if (event.dataTransfer.types) {
for (var i=0; i<event.dataTransfer.types.length; i++) {
if (event.dataTransfer.types[i] == "Files") {
return true;
}
}
}
return false;
}
function handleDragEnter(e) {
e.preventDefault();
if (containsFiles(e)) {
// The drag event contains files
// Do something
} else {
// The drag event doesn't contain files
// Do something else
}
}
当您将文件放入drop <div>
(或者您正在使用的任何元素作为dropzone)时,您将使用事件drop
的侦听器来读取某些文件属性,例如名称,大小,类型和上次修改日期。
要检测文件是否是文件夹,您将:
type == ""
,因为文件夹没有类型。size%4096 == 0
,因为文件夹的大小倍数为4096字节(即4KiB)。例:
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
var files = e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) { // iterate in the files dropped
if (!f.type && f.size%4096 == 0) {
// The file is a folder
// Do something
} else {
// The file is not a folder
// Do something else
}
}
}
已知问题:由于这些文件夹实际上是文件,因此这是将它们与另一种文件区分开来的唯一方法。虽然此方法无法确定文件是文件夹:它可能是没有扩展名且大小为0或N x 4096B的文件。
以下是一些工作示例,以了解我上面所说的内容并自行测试。在运行它们之前,请确保您的浏览器为supports drag and drop features。玩得开心:
这是关于Dropping -on drop事件的工作 - (请注意,这不适用于dragover事件):
isDraggedItemIsFile = function(e) {
// handle FF
if (e.originalEvent.dataTransfer.files.length == 0) {
return false;
}
// handle Chrome
if (e.originalEvent.dataTransfer.items) {
if (typeof (e.originalEvent.dataTransfer.items[0].webkitGetAsEntry) == "function") {
return e.originalEvent.dataTransfer.items[0].webkitGetAsEntry().isFile;
} else if (typeof (e.originalEvent.dataTransfer.items[0].getAsEntry) == "function") {
return e.originalEvent.dataTransfer.items[0].getAsEntry().isFile;
}
}
return true;
};
$forms.on('drop', function(e) {
if (isDraggedItemIsFile(e)) {
// do something if file
} else{
// is directory
}
});
在FF V49,Chrome V55,Edge V25上测试
您可以使用FileReader或webkitGetAsEntry()将文件与文件夹分开
ie11不支持webkitGetAsEntry(),所以请记住这一点!
代码如下所示:
onDrop(event) {
let files = event.dataTransfer ? event.dataTransfer.files : 'null';
for(let i = 0, file; file = files[i]; i++) {
var reader = new FileReader();
reader.onload = function (e) {
console.log('it is a file!');
};
reader.onerror = function (e) {
console.log('it is a folder!');
};
reader.readAsText(file);
}
}
我能够将整个Mimetype的东西拖到我的页面上。对于文件夹,Mimetype似乎是空白的,所以也许你可以通过这种方式区分它。
部分代码(从React中提取):
function handleDragOver(ev: DragEvent) {
ev.preventDefault();
ev.dataTransfer!.dropEffect = 'copy';
console.log(Array.from(ev.dataTransfer.items).map(i => [i.kind,i.type].join('|')).join(', '));
}
document.addEventListener('dragover',handleDragOver);
输出如下:
file|image/x-icon, file|image/jpeg, file|application/vnd.ms-excel
当我在页面上拖动3个文件时。
不确定它是否仅适用于localhost,我还没有在任何地方上传,但它完全正常工作。