首页 > 建站教程 > JS、jQ、TS >  js获取拖拽文件夹中所有的文件正文

js获取拖拽文件夹中所有的文件

js获取拖拽文件夹中所有的文件,遍历拖拽的文件及文件夹中所有的文件,并展示出来:


一、效果说明

从本地拖拽文件(夹)到浏览器中,展示包含的所有文件。

js拖拽文件夹


二、分析

需要先获取拖拽的内容,得到一个文件(夹) list 。循环 list ,对于其中的每一项,如果是文件,那么直接获取;如果是文件夹,则需要递归读取内部文件。


在 drop 事件中可以得到 e.dataTransfer ,它有两个属性可以获得拖拽内容:

    files :被拖动到浏览器窗口中的本地文件列表

    items :拖动操作中被拖动项的 DataTransferItem 对象。(拖动项可能是文件,也可能是别的)


先说结论:不能用 e.dataTransfer.files ,必须用 e.dataTransfer.items


三、为什么不能用 e.dataTransfer.files ?

e.dataTransfer.files 是 FileList 对象,是伪数组对象(有 length 属性,可通过索引获取元素)。遍历得到 File 对象

dropArea.addEventListener("drop", e => {
    let files = e.dataTransfer.files; // FileList 对象
    for (let i = 0; i <= files.length - 1; i++) {
        let file = files.item(i); // File 对象
        console.log(file); 
    }
    e.preventDefault();
});


最终,我们拿到的是一个个 File 对象。但是,无法判断一个 File 对象是文件夹还是内容。


File 对象属性如下:

js拖拽文件夹


不能用 type 来判断,因为不靠谱:


type 属性:浏览器不会实际读取文件的字节流,而是根据文件的扩展名来判断。而且,file.type 仅仅对常见文件类型可靠,不常见的文件扩展名会返回空字符串。

js拖拽文件夹


总结:用 e.dataTransfer.files 最终获取到的是 File 对象,无法判断一个 File 对象是文件还是文件夹,所以不能用!


四、用 e.dataTransfer.items

e.dataTransfer.items 是 DataTransferItemList 对象,是伪数组对象(有 length 属性,可通过索引获取元素)。遍历得到 DataTransferItem 对象。

dropArea.addEventListener("drop", e => {
    // DataTransferItemList 对象,是伪数组对象
    let items = e.dataTransfer.items;
    for (let i = 0; i <= items.length - 1; i++) {
        //  DataTransferItem 对象 
        let item = items[i]; 
    }
    e.preventDefault();
});


每个对象,可能是文件,也可能是字符串,通过 kind 属性可以判断。

dropArea.addEventListener("drop", e => {
    let items = e.dataTransfer.items;
    for (let i = 0; i <= items.length - 1; i++) {
        let item = items[i];
        // 通过 kind 属性可以判断当前的 DataTransferItem 对象是文件还是字符串
        if (item.kind === "file") { 
        }
    }
    e.preventDefault();
});


使用 webkitGetAsEntry 方法:获取到一个 FileSystemFileEntry 对象或 FileSystemDirectoryEntry 对象。这两种都继承自 FileSystemEntry。

dropArea.addEventListener("drop", e => {
    let items = e.dataTransfer.items;
    for (let i = 0; i <= items.length - 1; i++) {
        let item = items[i];
        if (item.kind === "file") {
            // FileSystemFileEntry 或 FileSystemDirectoryEntry 对象
            let entry = item.webkitGetAsEntry();
            // 递归地获取entry下包含的所有File
            this.getFileFromEntryRecursively(entry);
        }
    }
    e.preventDefault();
});


getFileFromEntryRecursively 方法

使用 FileSystemEntry 对象的 isFile 属性,判断是文件还是文件夹。

getFileFromEntryRecursively(entry) {
    if (entry.isFile) {
         // 文件
    } else {
         // 文件夹
    }
}


如果是文件的话,entry 的具体类型就是 FileSystemFileEntry,用 file 方法获得一个 File 对象:

FileSystemFileEntry.file(successCallback[, errorCallback]);


successCallback 中会传入 File 对象。

注意 :这个 File 对象的相对路径是空(webkitRelativePath是空字符串),所以如果想要保留拖拽的层级结构,只能从 entry 中获取

getFileFromEntryRecursively(entry) {
   if (entry.isFile) {
      // 文件
      entry.file(
          file => {
          // 想要保留拖拽的层级结构的话,只能从 entry 中获取
            this.addFileToList({ file, path: entry.fullPath });
          },
          e => { console.log(e); }
     );
   } else {
     // 文件夹
   }
}


如果是文件夹的话,entry 的具体类型就是 FileSystemDirectoryEntry ,可以使用 createReader 方法获得一个 FileSystemDirectoryReader 对象。reader 的 readEntries 方法,获取这个 entry 下的子级 entries。

getFileFromEntryRecursively(entry) {
      if (entry.isFile) {
        entry.file(
          file => {
            this.addFileToList({ file, path: entry.fullPath });
          },
          e => { console.log(e); }
        );
      } else {
        let reader = entry.createReader();
        reader.readEntries(
          entries => {
            entries.forEach(entry => this.getFileFromEntryRecursively(entry));
          },
          e => { console.log(e); }
        );
      }
}


本文为CSDN博主「呀呀夫斯基」的原创文章,原文链接:https://blog.csdn.net/tangran0526/article/details/104108551