uni-app H5端拖拽上传需用div模拟拖拽区并绑定dragover/drop事件,调用preventDefault()和stopPropagation(),从dataTransfer.files获取文件,通过FormData+uni.uploadFile上传;H5平台必须使用files数组而非filePath,且需条件编译隔离平台差异。

uni-app H5端拖拽上传必须绕开 input type="file"
原生 input 标签不支持拖拽事件监听,也不能响应 dragover、drop 等行为。强行给它加 ondragover 没用,浏览器会直接拦截默认行为并拒绝触发 drop。真实可行路径是:用普通 <div> 模拟拖拽区 → 手动绑定事件 → 从 <code>event.dataTransfer.files 拿文件 → 走 FormData + uni.uploadFile。
关键点:
- 必须在
dragover回调中调用event.preventDefault()和event.stopPropagation(),否则drop不会触发 -
drop事件里只能从event.dataTransfer.files取文件,不能用event.target.files(那是input的) - 多文件上传时,
files是FileList,需转成数组再遍历,避免直接用for...in遍历出原型链属性 - 拖拽区样式建议加
outline: 2px dashed #007AFF和transition: outline 0.2s,提升反馈感
拖拽后怎么传给 uni.uploadFile?H5平台不用 filePath
uni.uploadFile 在 H5 平台下会忽略 filePath 参数,只认 files 数组。很多人卡在这儿——写了 filePath: file 却一直报错或静默失败。正确写法是把 File 实例塞进 files 字段,并显式指定 name(否则后端收到的字段名可能是 blob)。
示例片段:
const formData = new FormData();
formData.append('file', file, file.name); // 第三个参数是服务端看到的原始文件名
<p>uni.uploadFile({
url: '<a href="https://www.php.cn/link/f142c6067e6345134c6728f299cf4c1e">https://www.php.cn/link/f142c6067e6345134c6728f299cf4c1e</a>',
files: [{ // 注意:是数组,每个元素含 file + name
file: file,
name: 'file' // 后端接收字段名,和 formData.append 的第一个参数一致
}],
formData: { // 其他字段仍走 formData
userId: '123',
category: 'doc'
},
success: res => {
console.log('上传成功', res);
},
fail: err => {
console.error('上传失败', err);
}
});注意:files 是 uni-app H5 专属字段,App 和小程序端不识别;跨平台项目务必用条件编译隔离。
拖拽上传容易漏掉的三类错误处理
用户拖一个超大视频进来、拖了 20 个压缩包、或中途关了页面——这些场景下没做防御,UI 就会卡死或报错不提示。
- 文件大小限制必须在
drop后立刻校验,别等进uploadFile再靠服务端返回 413;建议单文件 ≤50MB,用file.size > 50 * 1024 * 1024判断 - 重复拖拽同一文件(比如误操作两次 drop),应去重:用
file.name + file.lastModified做简易 key,存入 Set 缓存 - 没处理
fail和complete回调:上传失败时 loading 状态不会自动关闭,用户可能反复点击;complete是唯一能统一收尾的地方(比如隐藏 loading、重置拖拽区样式)
移动端 H5 拖拽上传实际不可用,得降级为点击
绝大多数安卓 WebView 和 iOS Safari 对 dragstart/drop 支持极差,甚至完全禁用。实测在微信内置浏览器、QQ 浏览器、部分国产厂商浏览器中,拖拽区能高亮但松手就无反应。这不是代码问题,是 WebView 原生限制。
解决方案只有两个:
- 用
uni.getSystemInfo检测platform === 'devtools'或webView类型,仅在桌面 Chrome/Firefox 显示拖拽区,其他环境强制显示「点击上传」按钮 - 按钮内部仍用动态创建
input+click()触发,兼容性最稳;可配合accept属性限制类型,如accept=".pdf,.doc,.xlsx,image/*"
真正麻烦的是混合场景:同一个 H5 页面既要支持 PC 端拖拽,又要兜底移动端点击,且不能让两套逻辑互相污染。最轻量的做法是用一个 isDragSupported 响应式变量控制 DOM 渲染分支,别试图复用同一套事件监听器。


















