游乐游手机版
首页/前端开发/文章详情

利用draggable与Dropzone实现多文件异步队列上传

时间:2026-07-10 06:45
实现多文件拖动上传需在dragover和drop事件中调用preventDefault()。利用Promise队列控制并发(建议3-5个)避免请求超载。上传前通过file type和file size同步校验文件类型与大小。注意dataTransfer files为只读快照,移动端不支持拖拽需降级为点击。
导致 dragover 不触发 drop 的根本原因在于未在 dragover 事件中调用 e.preventDefault(),浏览器默认会阻止投放行为。必须同时监听 dragover 和 drop 两个事件,并在各自回调中均调用 preventDefault();当子元素存在时,需为其添加 pointer-events: none 以确保事件冒泡不被阻断。此外,文件上传场景无需为 HTML 元素设置 draggable="true"。

HTML全局属性draggable与原生Dropzone结合的多文件拖动异步队列传输

dragover 不触发 drop 的根本原因

不少开发者在实现拖放上传时都会遇到这样的困惑:明明写了 drop 事件的监听,但文件拖入目标区域后毫无响应。绝大多数情况下,问题根源都出在 dragover 事件里——没有调用 e.preventDefault()

浏览器对拖放操作有一套默认行为:它会将拖入的文件视为“打开”或“下载”动作,而非交给页面上的 drop 事件处理。必须通过 preventDefault() 明确告知浏览器:“这片区域由我接管,请勿干预。”否则连 drop 事件都不会被派发。

常见的错误写法:只给 drop 绑定了监听器,却遗漏了 dragover,或者虽然监听了 dragover 但未调用 preventDefault()

  • 核心原则:dragoverdrop 都必须监听,且两者内部均需调用 e.preventDefault()
  • dragenterdragleave 属于增强体验的辅助事件,主要用于视觉反馈(如添加高亮类),与功能逻辑无关
  • 如果 drop 区域内包含子元素(例如

    或图标),这些子元素会拦截事件冒泡。最简单的解决方案:为子元素设置 pointer-events: none,让事件直接冒泡到容器层

draggable="true" 在文件上传中其实不需要

当用户从本地文件系统将文件拖拽到网页时,操作的对象是操作系统中的文件,而不是网页内某个

元素。因此完全不需要为任何 HTML 元素设置 draggable="true" 属性——该属性用于拖拽排序、页面内元素拖拽等场景(例如可拖拽列表),与文件上传完全是两回事。

真正的文件拖放上传依赖浏览器对操作系统文件的原生支持。只需在目标区域上监听 dragoverdrop,就能从 e.dataTransfer.files 中获取文件列表。

  • 设置 draggable="true" 虽然不会报错,但毫无必要,甚至可能让人误以为“需要从页面内拖出某个元素”
  • 如果希望用户从页面内拖拽图片或文本到上传区,那才需要结合 dragstartdataTransfer.setData() 实现,这是另一套逻辑,与本地文件上传无关
  • 文件上传场景中,e.dataTransfer.files 是一个只读的 FileList 对象,无法增删,只能遍历处理

多文件上传必须用异步队列,别直接 forEach + fetch

最容易踩的坑:用户一次性拖入 20 个文件,开发者直接使用 Array.from(files).forEach(file => upload(file)) 并发发起所有上传请求。后果呢?浏览器连接数被瞬间打满,后端触发限流,部分请求被静默丢弃——尤其在用户拖入 20+ 文件时,控制并发数至关重要。

推荐的方案是用 Promise 队列,每次只并发 3–5 个请求,其余文件排队等待空闲 slot:

function uploadQueue(files, maxConcurrency = 3) {  const queue = Array.from(files);  const results = [];  let active = 0;  return new Promise((resolve) => {    function next() {      if (queue.length === 0 && active === 0) return resolve(results);      if (active >= maxConcurrency || queue.length === 0) return;            active++;      const file = queue.shift();      uploadOne(file).then(res => {        results.push({ file: file.name, success: true, ...res });      }).catch(err => {        results.push({ file: file.name, success: false, error: err.message });      }).finally(() => {        active--;        next();      });    }    while (active < maxConcurrency && queue.length) next();  });}
  • uploadOne(file) 内部建议使用 FileReader.readAsArrayBuffer(file),而不是 readAsDataURL,因为大文件生成超长 base64 字符串会卡住 UI 线程
  • 上传前务必进行文件类型和大小校验,直接读取 file.typefile.size 即可(同步操作,无需 FileReader)
  • 后端接收的字段名必须与接口约定一致,例如 formData.append('files', file),否则 multipart 解析会失败

drop 区域样式与兼容性细节

视觉反馈做不好的话,用户根本不知道哪些区域可拖放、拖入后是否生效。但仅靠 CSS :hover 不够,必须通过事件驱动状态变化。

  • dragenter 触发时添加高亮类(例如 dropZone.classList.add('drag-over')),在 dragleave 时移除。注意:鼠标快速划过子元素可能多次触发 dragleave/dragenter,建议加入防抖处理,或者利用 event.relatedTarget 判断是否真的离开了容器
  • IE11 不支持 dataTransfer.files,不过该浏览器基本已淘汰;Safari 对 dragoverpreventDefault() 要求更严格,务必确保监听器正确绑定到目标 DOM 节点上
  • 移动端(iOS/Android 浏览器)不支持文件拖放 API,必须降级为点击 的形式,不能指望拖放功能覆盖全平台

还有一个容易忽略的细节:drop 事件中获取的 e.dataTransfer.files 是实时快照,而非引用。如果上传过程中需要过滤某些文件(例如根据大小),不要试图直接修改 files 对象——它是只读的,只能自行新建一个数组来处理。

来源:https://www.php.cn/faq/2743889.html
上一篇Select2下拉框键盘导航与选中高亮实现方法 下一篇Layui表单提交前自动去除所有Input空格
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
DCloud平台选型指南 适用场景与核心差异详解
前端开发 · 2026-07-10

DCloud平台选型指南 适用场景与核心差异详解

DCloud是一个围绕跨平台开发与流应用构建的技术生态,旨在帮助前端开发者使用Web技术开发高性能移动应用。其核心产品包括集成开发环境HBuilderX和基于Vue js的uni-app框架,支持一套代码发布至iOS、Android、Web及多端小程序。相比ReactNative和Flutter,uni-app在多端覆盖和Vue技术栈学习成本上具有优势,适合

DCloud使用教程与常见问题解决方案详解
前端开发 · 2026-07-10

DCloud使用教程与常见问题解决方案详解

DCloud提供跨平台应用开发方案,核心为HBuilderX与uni-app框架。开发者使用Vue js语法编写代码,可编译发布至iOS、Android、Web及小程序等多端。流程涵盖项目创建、开发调试与真机预览。常见问题如设备识别、编译失败等可通过检查设置、查看日志与条件编译解决。应用完成后支持云打包生成安装包。

DCloud新手入门教程 从零开始快速掌握开发技巧
前端开发 · 2026-07-10

DCloud新手入门教程 从零开始快速掌握开发技巧

DCloud是一个基于Web技术的跨平台应用开发平台,允许开发者使用HTML5等语言编写代码,并编译为iOS、Android及小程序应用,实现“一次编写,多端发布”。开发需使用HBuilderX,基于Vue js进行页面开发,平台提供丰富组件与API,并支持插件市场扩展功能。

DCloud新手入门指南从零开始了解这个开发平台
前端开发 · 2026-07-10

DCloud新手入门指南从零开始了解这个开发平台

DCloud是一个移动应用开发平台,旨在帮助前端开发者使用Web技术高效开发性能接近原生的跨平台应用。其核心产品包括HBuilderX开发环境和基于Vue js的uni-app框架,可实现一次开发、多端发布。平台通过完整工具链和插件生态降低开发门槛,适合需要快速迭代、覆盖多端的应用场景。

Zepto实战项目优化技巧与应用场景详解
前端开发 · 2026-07-10

Zepto实战项目优化技巧与应用场景详解

Zepto js作为轻量级JavaScript库,专为移动端优化,体积仅约10KB。它支持模块化定制,可按需构建以减小体积。使用时需减少DOM操作、善用事件委托,并可混合原生API提升性能。Zepto能融入现代工程流,但需注意其与jQuery的API差异及兼容性限制,适合在移动端性能优先的场景中替代jQuery。