首页 文章

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

提问于
浏览
54

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

例如:

ondrop 事件中,有一个名为 MouseEvent 的参数,其中有一个名为 dataTransfer 的字段,其中列出了文件( .files )或项目( .items ),具体取决于浏览器,我可以在ChromeFirefox中读取它 . 但是,对于 dragoverdragenter 事件,这些字段( .files.items )为空 . 问题是 I need that information while dragging, not dropping .

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

背景研究

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

WebKit,以及Chrome,对于何时可以调用getData非常严格 . 你不允许在dragstart或dragover中执行此操作 . 我认为这是规范的错误 .

但答案是2012年和 I can't find actual updated information on the topic ,所以我正在寻找有关此问题的最新信息 .

4 回答

  • 85

    TL; DR你不能:(

    如果您想知道为什么这个问题仍未得到接受的答案,您可以阅读OP创建的这个元问题,以及我的答案 .

    HTML5中的文件拖放

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

    拖动

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

    • dragenter

    • dragover

    • dragend

    • dragleave

    鉴于这些是 drag 事件, event.dataTransferfiles 属性将具有 length == 0 或为空( null ) .

    您无法在拖动事件中读取文件详细信息,也无法检查它们是否为文件夹 . 这不是一个错误,它是一种安全措施 .

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

    但是,您仍然可以通过迭代数组 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 == "" ,因为文件夹没有类型 .

    • 检查文件大小是否为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
            }
        }
    }
    

    KNOWN ISSUE: 由于这些文件夹实际上是文件,因此这是将它们与另一种文件区分开来的唯一方法 . 虽然此方法无法确定文件是文件夹:它可能是没有扩展名且大小为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

    您可以使用 FileReaderwebkitGetAsEntry() 将文件与文件夹分开

    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

相关问题