如何区分文件或文件夹在被删除之前是否被拖动?

问题描述 投票:55回答:4

我试图检测是否在dragoverdragenter事件中拖动了文件夹或文件。

For example:

ondrop事件中,有一个名为MouseEvent的论据,其中有一个名为dataTransfer的字段,其中列出了文件(.files)或项目(.items),具体取决于浏览器,我可以在ChromeFirefox中读到它。然而,对于dragoverdragenter事件,那些领域(.files.items)是空的。问题是我在拖动时需要这些信息,而不是丢弃。

注意:对于文件和文件夹,event.dataTransfer.types[i] === "Files"true

Background Research

我发现the following answer部分适合我的问题:

当你可以调用getData时,WebKit,以及Chrome,是非常严格的限制。你不允许在dragstartdragover内进行。我认为这是规范的错误。

但答案是从2012年开始,我无法找到有关该主题的实际更新信息,因此我正在寻找有关此问题的最新信息。

javascript html5 drag-and-drop directory
4个回答
89
投票

TL; DR你不能:(

如果你想知道为什么这个问题还没有得到一个可接受的答案,你可以阅读由OP和this meta question创建的my answer

File drag/drop in HTML5

我在这个主题的许多文档中做了一些研究,并在各种浏览器上自己测试了,所以我决定总结一下我所知道的关于文件拖放的所有知识。

拖延

拖动文件时可以使用一些侦听器,例如:

  • dragenter
  • dragover
  • dragend
  • dragleave

鉴于这些是drag事件,filesevent.dataTransfer属性要么有length == 0要么是空的(null)。

You can't read files details in a drag event and you can't check if they are folders. This is not a bug, it's a security measure.

想象一下,您可以在拖动事件中读取文件:即使用户不想将文件上传到您的站点,您也可以阅读所有内容。认真对待它是没有意义的。想象一下,您正在将文件从桌面拖到另一个文件夹,并且不小心将其拖动到网页中:现在网页会读取您的文件并将您的个人信息存储在其服务器上......这将是一个巨大的安全漏洞。

但是,您仍然可以通过迭代数组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的侦听器来读取某些文件属性,例如名称,大小,类型和上次修改日期。

要检测文件是否是文件夹,您将:

  1. 检查文件是否有type == "",因为文件夹没有类型。
  2. 检查文件大小是否为4096的倍数: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。玩得开心:


0
投票

这是关于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上测试


0
投票

您可以使用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);
    }

}

0
投票

我能够将整个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,我还没有在任何地方上传,但它完全正常工作。

MDN docs on DataTransferItem

© www.soinside.com 2019 - 2024. All rights reserved.