信息发布→ 登录 注册 退出

如何用Javascript实现拖放功能与文件上传?

发布时间:2026-01-11

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

直接用 dragover + drop 事件就能实现基础拖放,但真正能上传文件的完整链路,必须处理好三件事:阻止默认行为、读取 DataTransfer 对象、用 FormData 发送请求。漏掉任意一步,拖进去就啥也不发生。

为什么拖进页面没反应?preventDefault() 必须加在 dragover

浏览器对 dragover 事件有默认拦截策略——不阻止它,就根本触发不了 drop。这不是可选项,是硬性前提。

  • dragenterdragover 都要监听,但只有 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.filese.dataTransfer.items 怎么选?

两者都能取文件,但行为差异明显:filesFileList(只含本地文件),itemsDataTransferItemList(支持文件、文本、URL 等多种类型,且可递归读取目录)。

  • 纯文件上传场景,优先用 e.dataTransfer.files —— 简单、兼容性好、无权限问题
  • 需要支持拖入整个文件夹?必须用 items + webkitGetAsEntry()(Chrome/Safari),且需用户授权(fileSystem API 已废弃,仅剩此路径)
  • 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 上传时,fetchXMLHttpRequest 有啥区别?

本质没区别,但 fetch 默认不发 Content-Type 头(由浏览器自动设为带 boundary 的 multipart),而 XMLHttpRequest 若手动设了 Content-Type 反而会破坏边界符,导致后端解析失败。

  • 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 回调里手动做。前端拦不住恶意文件,但至少别让超大文件卡死浏览器再报错。

标签:# javascript  # java  # 前端  # go  # 浏览器  # app  # safari  # 后端  # stream  # 区别  # 为什么  
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!