点击选取文件夹
我们知道,选取文件可以通过以下方式:
1
| <input type="file" multiple/>
|
其实,想要选取文件夹只需要加上 webkitdirectory 属性:
1
| <input id="inputFile" type="file" multiple webkitdirectory/>
|
现在可以选中文件夹了,那么怎么获取文件夹里的文件呢?方法和获取文件一样,只不过变成了包含多个文件的列表。代码如下:
1 2 3 4 5 6 7 8 9
| window.onload = function() { const input = document.getElementById("inputFile"); input.onchange = event => { const fileList = event.currentTarget.files; for (let file of fileList) { console.log(file.name, file.webkitRelativePath, file.size); } } }
|
拖拽文件夹(文件)
思路介绍
拖拽上传文件夹主要通过 drop 事件实现。
1
| box.addEventListener("drop", event => {});
|
这里我们主要用到 event.dataTransfer.items
属性,它是一个 DataTransferItemList 对象,若选中 n 个文件夹或文件,则它的 lenght 为 n。
DataTransferItemList 对象有一个 webkitGetAsEntry()
方法,该方法返回一个 FileSystemEntry 对象(包括 FileEntry 和 DirectoryEntry)。
每个 FileSystemEntry 对象都有 isFile
和 isDirectory
两个属性,便于判断是文件还是文件夹。它还有 fullPath
属性表示从选取的文件夹开始的路径。
如果是文件夹(DirectoryEntry),它有一个 createReader()
方法,可以创建一个 reader,reader 通过 readEntries()
方法获取文件夹中的内容,如下所示:
1 2
| reader.readEntries(results => {});
|
得到一个 FileSystemEntry 类型的数组(results)。
注意: 该方法是异步执行的。而且,在文件夹中的文件
数目小于 100 时,可以读取到文件夹中的每个文件,但当文件数量大于 100 时,它最多只能读取到 100 个文件。因此,建议用递归获取完整的 results。
1 2 3 4 5 6 7 8 9 10 11 12
| let fileEntryList = [];
const getFileEntries = function() { dirReader.readEntries(results => { if (results.length) { fileEntryList = fileEntryList.concat(results); getFileEntries(); } }); }
getFileEntries();
|
如果是文件(FileEntry),它有 file
方法,可以获取文件的信息。
1
| fileEntry.file(fileData =-> {});
|
fileData 中包含属的属性有:
- name:文件名
- size:文件大小
注意:该方法也是异步执行的。
代码
html:
1 2
| <div id="box">拖拽上传(可选多个文件夹)</div> <ul id="list"></ul>
|
js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| const box = document.getElementById("box");
box.addEventListener("dragover", e => { e.preventDefault(); e.stopPropagation(); });
box.addEventListener("drop", e => { e.preventDefault(); e.stopPropagation();
dropedFileReader(e).then(fileList => { fileList.forEach(file => { const dom_ul = document.getElementById("list"); const dom_li = document.createElement("li"); dom_li.innerHTML = `name: ${file.name},path: ${file.fullPath},size: ${file.size}`; dom_ul.appendChild(dom_li); }); }); });
async function readRoll(fileEntryList) { for (let idx in fileEntryList) { const fileEntry = fileEntryList[idx]; if (fileEntry.isDirectory) { let result = await readDirectory(fileEntry); fileEntryList[idx] = result; await readRoll(result); } } }
function readDirectory(fileEntry) { return new Promise((resolve, reject) => {
const dirReader = fileEntry.createReader(); let fileEntryList = [];
const getFileEntries = function() { dirReader.readEntries(results => { if (results.length) { fileEntryList = fileEntryList.concat(results); getFileEntries(); } else { resolve(fileEntryList); } }); }
getFileEntries(); }); }
function readFileEntry(fileEntry) { return new Promise(resolve => { let fileData; fileEntry.file(data => { fileData = data; fileData.fullPath = fileEntry.fullPath; resolve(fileData); }); }); }
async function dropedFileReader(event) { let fileEntryList = [];
const dataTransferItemList = event.dataTransfer.items; for (let item of dataTransferItemList) { fileEntryList.push(item.webkitGetAsEntry()); }
await readRoll(fileEntryList);
fileEntryList = fileEntryList.flat(Infinity);
let fileList = []; for (let fileEntry of fileEntryList) { const fileData = await readFileEntry(fileEntry); fileList.push(fileData); }
return fileList; }
|