实现支持文件夹上传的Dropzone:表单为空问题求解
解决Dropzone文件夹上传表单为空的问题
问题根源
- 异步操作时序错误:
entry.file()是异步方法,循环结束后立即发送请求时,文件还未被添加到FormData,导致表单为空。 - 未处理文件夹递归:原代码仅判断文件项,未遍历文件夹内的子文件/子文件夹,无法实现文件夹上传。
- 路径拼接错误:
file.webkitRelativePath已包含完整相对路径(含文件名),额外拼接file.name会导致路径重复。
修改后的实现代码
dropZone.addEventListener('drop', function(e) { e.preventDefault(); hideDropZone(); const items = e.dataTransfer.items; uploadFiles(items); }); // 递归遍历文件/文件夹,收集所有文件的Promise async function collectFiles(entry) { const files = []; if (entry.isFile) { return new Promise(resolve => { entry.file(file => { files.push({ file, path: file.webkitRelativePath }); resolve(files); }); }); } else if (entry.isDirectory) { const reader = entry.createReader(); return new Promise((resolve, reject) => { function readEntries() { reader.readEntries(async (entries) => { if (entries.length === 0) { resolve(files); return; } for (const subEntry of entries) { const subFiles = await collectFiles(subEntry); files.push(...subFiles); } readEntries(); // 处理readEntries分批返回的目录项 }, reject); } readEntries(); }); } return files; } async function uploadFiles(items) { const formData = new FormData(); const allFiles = []; for (const item of items) { const entry = item.webkitGetAsEntry(); if (entry) { const files = await collectFiles(entry); allFiles.push(...files); } } allFiles.forEach(({ file, path }) => { formData.append('files', file, path); }); const request = new XMLHttpRequest(); request.open('POST', `/u?d=${get('d')}`); request.send(formData); }
关键修改说明
- 异步时序修正:使用
async/await和Promise确保所有文件都添加到FormData后再发送请求。 - 文件夹递归遍历:新增
collectFiles函数,递归处理文件夹内所有子项,实现完整的文件夹内容收集。 - 路径参数修正:直接使用
file.webkitRelativePath作为FormData.append的第三个参数,保证文件路径正确。 - 完善目录读取:处理
readEntries分批返回目录项的情况,确保所有子文件/文件夹都被遍历到。
内容的提问来源于stack exchange,提问作者Bouloukaouze
相关产品推荐
相关产品推荐

