拖拽上传面板不能只靠<input type="file">,因其无法响应拖拽事件、自定义视觉反馈或拦截校验;需监听dragover/dragenter/dragleave/drop事件并阻止默认行为,用DataTransfer.files提取文件、Array.from转换、type/size校验,URL.createObjectURL预览,FormData上传,注意多文件、文件夹、浏览器兼容等边界情况。

拖拽上传面板为什么不能只靠 input[type="file"]
原生 <input type="file"> 无法响应拖拽事件,也不能自定义视觉反馈(比如高亮边框、预览缩略图),更没法拦截文件路径或校验类型/大小。想实现“把文件拖进来就上传”,必须用自定义元素接管整个流程。
如何监听 dragover 和 drop 事件并阻止默认行为
浏览器默认会打开拖入的文件(比如图片直接在新页显示),必须显式调用 event.preventDefault() 才能触发 drop。但只在 drop 里 prevent 不够——dragover 也得拦,否则根本进不了 drop 阶段。
-
dragover事件必须监听在目标容器上,且每次触发都要调用event.preventDefault() - 别漏掉
dragenter(用于首次进入时添加高亮样式),它不带自动取消默认行为 - 记得监听
dragleave清除高亮,否则鼠标移出区域但未松手时状态残留
从 DataTransfer.files 提取文件并做基础校验
event.dataTransfer.files 是 FileList,不是数组,不能直接用 map 或解构。常见误操作是把它当普通数组处理,导致校验逻辑失效。
- 用
Array.from(event.dataTransfer.files)转成数组再遍历 - 检查
file.type(如"image/jpeg")比后缀名可靠,但某些系统可能为空,需 fallback 到file.name.split('.').pop() -
file.size单位是字节,10MB 限制要写成10 * 1024 * 1024,别错写成10 * 1000 * 1000 - 上传前建议用
URL.createObjectURL(file)生成临时预览 URL,避免直接读取二进制内容
用 FormData 构造请求并处理上传失败
直接 fetch 传 File 对象会出错,必须包装进 FormData。后端接收字段名(如 "file")必须和后端约定一致,否则 400 或空文件。
立即学习“前端免费学习笔记(深入)”;
-
formData.append("file", file)—— 单文件;多文件用循环,每个都append("files", file) - 如果后端要求 JSON 格式,不要传
FormData,改用file.arrayBuffer()+JSON.stringify,但注意 base64 体积膨胀 - 上传失败时,
response.status可能是 400(校验失败)、413(超限)、500(服务异常),别只判断!ok - 别忘了在
finally里调用URL.revokeObjectURL(url)释放预览内存
拖拽上传真正的复杂点不在事件监听,而在边界情况:中途中断拖拽、快速连续拖入多个文件、用户拖进的是文件夹而非文件(event.dataTransfer.items 里可能含 directory 类型)、Safari 对 webkitGetAsEntry 的特殊处理——这些不显式处理,面板上线后就会卡住用户。



















