dragover事件必须调用event.preventDefault()才能启用自定义拖拽上传,否则drop事件不会触发;获取文件应使用dataTransfer.files而非items或types;校验文件需检查大小和扩展名;多文件上传推荐多次append到FormData。
浏览器对文件拖拽有默认处理逻辑:把文件拖进页面时,会直接打开或下载。要启用自定义上传,dragover 事件里必须调用 event.preventDefault(),否则后续的 drop 根本不会触发。
dragenter 和 dragover 都要监听,但只有 dragover 的 preventDefault() 是强制必需的drop 里阻止默认行为——那时已经晚了upload 组件是否已封装好这层逻辑;没封装的话需手动补上event.dataTransfer 看似有多个属性可选,但真正稳定读取用户拖入的文件列表,唯一可靠的是 files 属性。它返回一个 FileList,和 的 files 完全一致。
items 是实验性 API,部分浏览器(如 Safari)不支持 getAsFile(),且类型判断复杂types 只是 MIME 类型数组,不能用来读文件内容event.dataTransfer.files 即可,例如:const files = event.dataTransfer.files;
for (let i = 0; i < files.length; i++) {
const file = files[i];
console.log(file.name, file.size, file.type);
}虽然现代浏览器不强制要求 dropzone 属性,但某些旧版 Chrome 或 Electron 环境下,仅靠 JS 监听不够。更稳妥的做法是:给目标容器加 dropzone="copy",并确保它有明确宽高和背景(否则可能点不中、拖不进)。
dropzone 值只能是 copy、move 或 link,上传场景一律用 copy
display: flex 或 position: absolute 布局,注意父容器不能是 overflow: hidden,否则拖拽阴影显示异常前端拦截明显违规文件能减少无效请求。但注意:MIME 类型可伪造,file.type 仅作参考;真正可靠的校验必须由后端做,前端只是提升体验。
立即学习“前端免费学习笔记(深入)”;
if (file.size > 10 * 1024 * 1024) { /* 超过 10MB */ }
const ext = file.name.split('.').pop().toLowerCase(); if (!['jpg', 'png', 'pdf'].includes(ext)) { ... }
FormData.append('files', file) 多次追加,而非合并成一个 Blo
拖拽上传本身逻辑简单,真正容易出问题的是事件生命周期理解偏差和跨浏览器行为差异。特别是 Safari 对 dataTransfer.items 的限制、IE 完全不支持,以及 Electron 中 WebContents 的 drag-drop 权限配置——这些不在标准 HTML5 范围内,但实际项目里常踩坑。