必须在dragover和drop中均调用event.preventdefault(),否则浏览器默认将拖入文件视为导航行为(如打开或下载),导致datatransfer.files为空且drop不触发;dragover是许可门禁,需先放行才能进入drop阶段。

必须在 dragover 和 drop 两个事件中都调用 event.preventDefault(),缺一不可。只在 drop 里阻止,dragover 不处理,文件根本进不来——浏览器早就在松手前跳转或打开了。
为什么 dragover 不阻止,drop 就不会触发
浏览器把拖入文件默认当成「导航行为」:拖一张 PNG 进来,Chrome 直接在当前页打开预览;拖个 ZIP,就弹下载框。这个过程会清空 dataTransfer,导致 event.dataTransfer.files 始终为空。而 drop 事件能否触发,完全取决于 dragover 是否被允许——它不阻止,默认就是禁止放置,光标变“圆圈加斜杠”,用户根本拖不进来。
-
dragover是“许可门禁”,不是“取文件的地方”,但它必须放行 - 只给目标区域(比如
div#dropzone)绑dragover不够稳妥;如果用户拖到页面空白处再松手,drop仍可能触发默认行为 - 更保险的做法是在
document级别监听:document.addEventListener('dragover', e => e.preventDefault())
drop 事件里除了 preventDefault() 还要做什么
阻止默认行为只是第一步,drop 中真正要干的是从 event.dataTransfer.files 拿文件列表,然后塞进 FormData 发送。注意别误用 e.target.files——那是 <input type="file"> 的属性,拖拽场景下永远是 undefined。
- 直接读
e.dataTransfer.files,它是FileList类型,可遍历、可传给FormData.append() - 如果需要校验类型或大小,立刻在
drop回调里做,别等发请求时才报错 - 移动端不支持原生
drag/drop文件操作,这部分逻辑需降级为点击上传
常见错误现象和对应检查点
拖完没反应、控制台没报错、但 files.length === 0——大概率是以下某一条漏了:
-
dragover事件监听器没挂上,或挂了但没调e.preventDefault() - 用了
e.stopPropagation()却忘了preventDefault(),前者只管冒泡,后者才管默认行为 - 在
drop里写了e.preventDefault(),但dragover是在父元素上监听的,而父元素没设event.dataTransfer.dropEffect = 'copy',导致视觉反馈异常(虽然不影响功能,但用户可能不敢松手) - 测试时拖的是文件夹——
dataTransfer.files不包含子文件,需用items+webkitGetAsEntry递归读取(但兼容性差,一般建议禁用文件夹上传)
最易被忽略的一点:即使你绑对了事件、写全了 preventDefault(),如果目标区域没有设置明确的宽高(比如内容为空的 div),dragover 根本不会触发——因为没有可“悬停”的像素区域。加个 min-height: 200px 或 border: 1px dashed #ccc,问题常当场消失。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











