dragover 和 drop 事件中必须同时调用 preventDefault(),否则浏览器默认行为会阻止 drop 触发;文件从 dataTransfer.files 获取,用 FormData + fetch 上传且不设 Content-Type。

dragover 和 drop 必须同时调用 preventDefault()
浏览器默认会把拖进来的文件当链接或本地资源打开——图片直接显示、PDF 自动预览、文本弹下载,drop 事件压根不会触发。这不是 bug,是浏览器的保护机制。所以 dragover 和 drop 两个事件里都得写 e.preventDefault(),少一个就失败。
别信“只在 drop 里加就行”的说法:dragover 不阻止,默认行为会禁用整个放置区域,drop 根本收不到事件。
-
dragenter可加可不加,纯用来做视觉反馈(比如加个 class) -
dragleave容易误触发(鼠标划过子元素也会触发),新手建议先不用 - 目标容器不需要
draggable="true"——那是给“拖出元素”用的,不是“接收区”
从 dataTransfer.files 拿文件,别碰 items
event.dataTransfer.files 是标准、稳定、兼容性最好的路径;event.dataTransfer.items 虽然能读取剪贴板粘贴的文件,但 iOS Safari 和部分安卓 WebView 不支持,而且多层嵌套结构容易出错。
你只需要:
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 用
Array.from(e.dataTransfer.files)转成数组,方便filter/forEach - 用
file.type做初步过滤(如file.type.startsWith('image/')),但别依赖它做安全校验 - 用
file.size拦大文件(比如 >20MB),避免上传中途卡死或被服务端拒绝
上传用 FormData + fetch,别手动设 Content-Type
FormData 本身会自动生成 multipart boundary,如果手动设置 Content-Type: multipart/form-data,浏览器反而会删掉 boundary,导致后端解析失败,报 400 Bad Request 或空文件。
正确写法就三步:
- 新建
const formData = new FormData() - 循环追加:
formData.append('file', file)(单文件)或formData.append('files', file)(多文件同名字段) - 发起请求:
fetch('/upload', { method: 'POST', body: formData })—— 不传headers字段
服务端收到的就是标准 multipart 表单,PHP 用 $_FILES,Node.js 用 multer 或 busboy 都能直接接住。
极简样式只需控制 border + hover + highlight
所谓“极简”,不是没反馈,而是反馈干净:拖入时变色、释放后还原、无动画、无图标、无文字变化。CSS 只需三类状态:
- 默认态:
border: 2px dashed #999 - 悬停态(
dragover触发):border-color: #007cba - 高亮态(
dragenter可选):background: #f8fbff,但drop后立刻清除
别加 transition,别用 box-shadow,别塞“↑↑↑”箭头图——这些都会干扰用户对“可投放”的判断。真正的极简,是让用户一眼看出“这里能松手”,然后立刻进入下一步。


















