必须在dragover和drop中均调用e.preventDefault(),否则浏览器默认将拖入文件视为“打开”而非上传,导致drop被静默拦截;dragover是投放准入开关,未阻止其默认行为则drop永不触发。

拖放上传能用,但必须在 dragover 和 drop 两个事件里都调 e.preventDefault(),否则浏览器会直接打开文件或跳转,drop 根本不会触发。
为什么只绑 drop 没反应
常见现象是拖文件进去没日志、没预览、页面却跳到了一个图片地址或白屏。根本原因是 dragover 事件没阻止默认行为——浏览器把这次拖放当成“打开文件”处理了,drop 被系统静默拦截。
-
dragover是“准入开关”,不调preventDefault(),drop就永远不会执行 - 别在
document或body上监听,确保事件绑定到你实际想接收拖放的容器元素(比如id="drop-area"的<div>) - 如果用了 Vue/React,确认 ref 拿到的是真实 DOM 节点,虚拟节点上绑事件无效
dataTransfer.files 怎么安全取到文件
event.dataTransfer.files 返回的是只读的 FileList,不是数组,不能直接用 map 或 forEach。
- 先用
Array.from(event.dataTransfer.files)转成数组再遍历 - 校验类型别只写
file.type === 'image/jpeg',改用file.type.startsWith('image/'),否则.png.webp全被漏掉 -
file.size前端可做快速拦截,比如if (file.size > 50 * 1024 * 1024),避免大文件卡死页面 - 用户可能拖来文件夹或 .exe,
file.type可被伪造,仅作提示,服务端必须二次校验
用 FormData 上传时要注意什么
上传本身不难,但几个细节不注意就会 400 或后端收不到字段。
立即学习“前端免费学习笔记(深入)”;
-
FormData.append()的 key 名要和服务端约定一致,比如后端期待files[],就写formData.append('files[]', file) - 多个文件不要循环创建多个
FormData,一个实例 append 所有文件更稳妥 - 用
fetch发送时,**不要手动设置Content-Type头**,否则浏览器会删掉 boundary,导致后端解析失败 - 如果后端需要额外字段(如
user_id),也用append()加进去:formData.append('user_id', '123')
最易被忽略的一点:拖放区域如果嵌套在表单里,且没禁用默认提交,松手瞬间可能触发表单 submit,导致页面刷新。建议给容器加 onsubmit="return false" 或直接用 div 而非 form 作为 drop 区域。



















