js拖拽文件夹上传文件(附较完整注释)

scanFiles.js 通过drop事件获取文件夹中

经测试兼容新版chrome和safari浏览器。注意:chrome 每次只能读取100个文件,所以下边代码循环读取。

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
// 仅支持选择一个文件夹,并且不会递归上传
async function scanFiles(e) {
e.preventDefault()
const { items = [], files = [] } = e.dataTransfer

// 只上传第一个文件夹
const [item] = items
if (!item || !item.webkitGetAsEntry) return files

// 如果是文件直接返回文件
const entry = item.webkitGetAsEntry()
// 第一个类目是文件直接返回files,如果是文件夹下则返回第一层目录
return entry.isFile ? files : getEntryDirectoryFiles(entry)
}

// 获取文件夹中文件
function getEntryDirectoryFiles(entry) {
const reader = entry.createReader()
// 一次最多只能读100,防止出现文件夹内文件个数过多,加一个变量收集最新的结果
let res = []
return read()

async function read() {
const files = await new Promise((resolve, reject) =>
reader.readEntries((entries) => {
// 只上传一层文件,过滤文件夹中包含的文件夹
const fileEntries = entries.filter((entry) => entry.isFile)
const filesPromise = fileEntries.map((entry) => new Promise((resolve) => entry.file((file) => resolve(file))))
Promise.all(filesPromise).then(resolve)
}, reject)
)
// 保存当前读取文件
res = [...res, ...files]
// chrome浏览器一次读取最多获取100个文件,多于100个需要再次读取
if (files.length < 100) {
return res
}
return read()
}
}

拖拽文件夹上传测试

1
2
3
4
5
6
7
8
// 阻止浏览器打开新标签,ondrop/ondragover/ondragenter(最好加上这个防兼容问题)
window.ondragover = (e) => e.preventDefault()

// 获取文件夹
window.ondrop = async (e) => {
const files = await scanFiles(e)
console.log('获取到文件', files)
}