必须阻止dragover默认行为才能触发drop事件,再读取e.dataTransfer.files获取文件列表,最后用FormData发送请求;accept属性无效,校验须在drop回调中手动完成。

直接用 dragover + drop 事件就能实现基础拖放,但真正能上传文件的完整链路,必须处理好三件事:阻止默认行为、读取 DataTransfer 对象、用 FormData 发送请求。漏掉任意一步,拖进去就啥也不发生。
为什么拖进页面没反应?preventDefault() 必须加在 dragover
浏览器对 dragover 事件有默认拦截策略——不阻止它,就根本触发不了 drop。这不是可选项,是硬性前提。
-
dragenter和dragover都要监听,但只有dragover必须调用e.preventDefault() - 只阻止
dragenter没用;只阻止drop更没用(它压根不会触发) - 如果目标区域是
contenteditable或表单控件,可能还要额外处理dragleave防止样式错乱
const dropZone = document.getElementById('drop-area');
dropZone.addEventListener('dragover', (e) => {
e.preventDefault(); // 关键!没有这行,下面的 drop 永远不会来
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
const files = e.dataTransfer.files; // 这里才能拿到文件列表
});
e.dataTransfer.files 和 e.dataTransfer.items 怎么选?
两者都能取文件,但行为差异明显:files 是 FileList(只含本地文件),items 是 DataTransferItemList(支持文件、文本、URL 等多种类型,且可递归读取目录)。
- 纯文件上传场景,优先用
e.dataTransfer.files—— 简单、兼容性好、无权限问题 - 需要支持拖入整个文件夹?必须用
items+webkitGetAsEntry()(Chrome/Safari),且需用户授权(fileSystemAPI 已废弃,仅剩此路径) -
items在 Firefox 中对本地文件返回空getAsFile(),所以不能只依赖它
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
const files = e.dataTransfer.files; // ✅ 推荐:稳定获取 FileList
// const items = e.dataTransfer.items; // ⚠️ 要配合 entry 处理,且兼容性差
Array.from(files).forEach(file => {
console.log(file.name, file.size, file.type);
});
});用 FormData 上传时,fetch 和 XMLHttpRequest 有啥区别?
本质没区别,但 fetch 默认不发 Content-Type 头(由浏览器自动设为带 boundary 的 multipart),而 XMLHttpRequest 若手动设了 Content-Type 反而会破坏边界符,导致后端解析失败。
立即学习“Java免费学习笔记(深入)”;
- 用
fetch:完全不要设headers: {'Content-Type': ...},让它自动生成 - 用
XMLHttpRequest:调用xhr.send(formdata)即可,千万别xhr.setRequestHeader - 如需上传进度,
XMLHttpRequest.upload.onprogress更直接;fetch需配合ReadableStream+TransformStream,复杂度高得多
const formData = new FormData();
Array.from(files).forEach(file => formData.append('files', file));
// ✅ 正确:fetch 不设 Content-Type
fetch('/upload', { method: 'POST', body: formData });
// ✅ 正确:XHR 不设 header
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = e => console.log(${(e.loaded / e.total * 100).toFixed(0)}%);
xhr.open('POST', '/upload');
xhr.send(formData);
最易被忽略的是:拖放本身不校验文件类型或大小,accept 属性在拖放中完全无效,所有校验必须在 drop 回调里手动做。前端拦不住恶意文件,但至少别让超大文件卡死浏览器再报错。










