必须在 dragover 事件中调用 preventdefault(),否则拖拽失效;drop 事件中立即校验 file.size(单位字节)并限制阈值(如50mb),再结合 file.name 后缀与 file.type 双重校验类型。

拖拽上传前必须校验 File.size,否则用户可能卡在“已选择”却无响应
HTML5 拖拽(drop 事件)本身不拦截超大文件,浏览器会照常把 File 对象塞进 DataTransfer.files,但后续上传很可能失败或卡死。关键不是等后端报错,而是前端立刻拦住——靠读 file.size 字节值做判断。
常见错误现象:drop 后没反应、控制台静默、进度条不动、甚至页面假死(尤其 Chrome 加载几百 MB 文件时)。
- 校验必须放在
drop事件处理函数里,且在调用preventDefault()之后、真正处理文件之前 -
file.size是只读属性,单位是字节,别误用file.sizeMB这类不存在的字段 - 建议阈值设为 50 * 1024 * 1024(50MB),兼顾体验与多数接口限制;若后端允许更大,前端也别盲目放开,要考虑内存占用和用户等待感
- 注意 Safari 对超大
File对象的解析延迟,校验后加个setTimeout微任务再执行上传逻辑,能缓解卡顿
仅靠 accept 属性无法限制拖拽文件类型,必须手动检查 file.type 和扩展名
input[type="file"] 的 accept 只影响点击选择弹窗,对拖拽完全无效。用户拖一张 .exe 进来,file.type 可能为空或伪造,光靠它过滤极不可靠。
真实场景中,用户常拖错图标、压缩包、隐藏扩展名的文件,后端拒收时体验断层。
立即学习“前端免费学习笔记(深入)”;
- 先看
file.type,但别全信——空字符串或application/octet-stream很常见 - 必须 fallback 到
file.name后缀:用file.name.toLowerCase().endsWith('.pdf')等方式比正则更稳 - 图片类上传建议额外用
file.type.startsWith('image/')+ 后缀双校验,避免 .txt 改名成 .png 蒙混 - 注意 Windows 用户可能关掉“显示文件扩展名”,拖进来的是
report(实际是report.docx),此时file.name不含点,得靠file.type或后续二进制嗅探(后者成本高,一般不推荐)
dragover 事件里漏写 preventDefault(),整个拖拽就失效
这是最常被忽略的硬性前提:没有 event.preventDefault(),浏览器会按默认行为处理拖拽(通常是打开文件或导航到文件路径),drop 根本不会触发。
错误现象:拖文件到区域时鼠标变成“禁止”符号、松手没反应、控制台无日志、Network 面板安静如鸡。
- 必须在
dragover(以及可选的dragenter)里同步调用preventDefault() - 不能只写在
drop里——那时早过了时机 - 别在
dragover里做重操作(如读取file.size),它会高频触发,容易卡顿;只做轻量态更新(比如加个is-draggingclass) - 移动端不支持原生拖拽,这个逻辑无需适配,但要确保降级方案(如点击上传)可用
大文件分片上传前,别直接用 File.slice(),注意浏览器兼容性和参数顺序
想绕过单文件大小限制?分片是常用解法,但 File.slice() 在旧版 Edge 和 Safari 中行为不一,且参数顺序易错。
典型问题:file.slice(0, 1024*1024) 在 Safari 返回空 Blob,或切出错误长度。
- 优先用标准
file.slice(start, end)(注意是end,不是长度),不要用三参数形式(file.slice(start, length, type))——后者已废弃且兼容性差 - IE10/11 完全不支持
File.slice,需用webkitSlice或mozSlice兜底,但更稳妥的做法是检测并提示“请使用现代浏览器” - 切片大小建议设为 1–5MB,太小增加 HTTP 开销,太大失去分片意义;用
Math.min(chunkSize, file.size - start)防止最后一片越界 - 注意
Blob对象不能跨 iframe 或 Worker 直接传递,需用structuredClone或转成ArrayBuffer再传
事情说清了就结束。最常被绕过的其实是 dragover 里的 preventDefault(),一行代码漏掉,后面所有校验都白写。











