multiple属性原生支持多文件选择,但chrome/firefox/safari表现正常,旧edge及微信安卓webview等可能静默降级为单选;需用change事件获取filelist并手动构造formdata上传。

multiple 属性本身就能批量选择,但浏览器行为有差异
直接给 <input type="file"> 加 multiple 属性,用户点击后就能选多个文件——这是原生支持,不需要 JS 拦截或模拟。但要注意:Chrome/Firefox/Safari 在多选时默认显示「文件选择对话框」,而部分旧版 Edge 或移动端 WebView 可能只允许单选,即使写了 multiple 也无效。
验证是否生效最简单的方式是打开控制台,选完后执行:
document.querySelector('input[type="file"]').files.length如果大于 1,说明选择成功;为 0 或 1 则可能是用户没按住 Ctrl/Shift 多选,或系统限制。
- macOS Finder 中需按住
Cmd点击多选,Windows 资源管理器用Ctrl或Shift - 某些安卓 WebView(如微信内置浏览器)会忽略
multiple,只返回第一个文件,此时必须换方案(见下一条) -
accept属性可配合使用,比如accept="image/*,.pdf",但它不影响multiple是否生效
监听 change 事件才能拿到 files 列表
files 是只读的 FileList 对象,只有在 change 触发后才可用。别试图在页面加载时就读取它——那时还是空的。
常见错误是绑定 click 或 input 事件去取 files,结果拿不到数据。正确写法:
const input = document.querySelector('input[type="file"][multiple]');
input.addEventListener('change', (e) => {
const fileList = e.target.files; // 这才是真实选中的 FileList
console.log(fileList.length); // 打印数量
});
-
FileList不是数组,不能直接用map、forEach,得转成数组:Array.from(fileList) - 每个
file是File实例,含name、size、type、lastModified等属性 - 若用户取消选择(对话框点取消),
e.target.files仍为上次值,不会变为空——要靠判断length === 0来识别“未选中”
上传多个文件时,FormData 的 append 方式决定后端接收结构
后端能否收到多个文件,取决于你往 FormData 里怎么 append。常见两种模式:
- 全部塞进同一个字段名:
formData.append('files', file)循环调用 → 后端收到名为files的文件数组(如 Express 的req.files.files) - 用带索引的字段名:
formData.append('files[' + i + ']', file)→ 后端可能解析成files[0]、files[1]等独立字段 - 不推荐用
new FormData(formElement)自动收集,因为<input multiple>提交时,多数浏览器只把第一个文件传过去(历史兼容问题)
所以务必手动遍历 FileList 构造 FormData,再用 fetch 或 XMLHttpRequest 发送。
移动端真机测试比开发工具更重要
Chrome DevTools 的设备模拟器会假装支持 multiple,但真机上 iOS Safari 和微信安卓版经常静默降级为单文件。这不是 bug,是平台策略——iOS 为安全限制网页访问相册/文件系统深度。
- 微信内嵌浏览器(X5 内核)基本无视
multiple,只能靠拍照+上传分两次走 - iOS Safari 从 16.4 开始有限支持,但仅限于「从文件 App 选择」,从照片图库选仍只返回一个
- 如果业务强依赖多文件上传,得准备降级方案:比如让用户逐个点选,或改用第三方 SDK(如腾讯云 COS 的直传组件)
别在没连真机的情况下就宣布“功能已上线”。










