drop事件中通过event.datatransfer.files获取多文件,它是只读filelist;拖拽文件夹需用datatransfer.items结合getasentry递归读取,注意浏览器兼容性。

drop 事件里怎么拿到多个文件
拖拽多个文件进页面时,drop 事件的 dataTransfer.files 是一个 FileList 对象,天然支持多文件——它不是数组,但可以用 [...files] 展开或用 Array.from(files) 转成数组操作。
常见错误是只取 files[0] 或误以为要循环读取 dataTransfer.items(那是用于处理拖拽文本、链接等混合内容的,上传文件优先用 files)。
- ✅ 正确方式:
const files = event.dataTransfer.files;直接使用 - ⚠️ 注意:
files是只读类数组,不能.push()或.splice() - ⚠️ 拖拽文件夹在部分浏览器(如 Chrome)会返回空
files,需额外检查items中是否有webkitGetAsEntry(见下一条)
如何兼容拖拽文件夹(含子目录)
原生 dataTransfer.files 不包含文件夹结构,拖入文件夹时 Chrome/Firefox 可能返回 0 个文件。必须通过 dataTransfer.items 遍历并调用 getAsEntry() 递归读取。
关键点:只有 Chrome 和 Edge 支持 webkitGetAsEntry,Firefox 使用 getAsEntry(无前缀),Safari 基本不支持文件夹拖拽——得提前告知用户或禁用该功能。
- 先遍历
event.dataTransfer.items,对每个item调用item.webkitGetAsEntry?.() || item.getAsEntry?.() - 拿到
entry后,用entry.isDirectory判断,再用entry.createReader().readEntries()递归读取 - ⚠️ 递归深度大时可能卡 UI,建议加
setTimeout分片处理,或限制最大文件数(如if (fileCount > 100) return)
阻止默认行为和 dragover 为什么必须 preventDefault
不阻止 dragover 和 drop 的默认行为,浏览器会直接打开文件(图片跳转、PDF 下载),根本不会触发你的上传逻辑。
- ❌ 错误写法:
element.addEventListener('dragover', () => console.log('hover'))—— 缺少preventDefault() - ✅ 正确写法:
element.addEventListener('dragover', e => { e.preventDefault(); }) - ⚠️
dragenter不需要preventDefault,但dragover必须有,否则拖拽悬停几秒后光标变“禁止”图标,松手就失效 - ? 小技巧:可以只在
dragenter时加一个isDragging标记,在dragleave清除,避免重复高亮;但dragover的preventDefault不能省
上传前校验和分片上传要不要在这里做
拖拽结束只是获取文件列表的起点,真正上传前的校验(类型、大小、重复名)应该在 drop 回调里同步完成,失败就立刻提示,别等发起请求才报错。
- 文件大小限制建议用
file.size > 500 * 1024 * 1024(500MB)这类硬判断,别依赖后端返回 - 类型校验别只看
file.type(可能为空或伪造),用file.name.match(/\.(jpg|png|pdf)$/i)辅助判断扩展名 - 如果要用分片上传(如大文件断点续传),
drop阶段只做预处理(生成唯一 file_id、计算 hash 前几块),不要立刻切片——切片和上传应交给后续队列控制 - ⚠️ 多文件同时上传时,别用
for...of+await fetch串行发请求,容易超时;用Promise.allSettled(files.map(uploadOne))并发更稳妥
真正麻烦的是跨浏览器对文件夹的支持差异和大文件内存占用——Chrome 能读深层目录,Firefox 最多两层,Safari 基本放弃;而一次性读取几百 MB 文件的 FileReader.readAsArrayBuffer 可能触发 OOM,这些细节比拖拽本身更值得花时间兜底。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











