带multiple属性的file输入框如何支持分次选单文件并累积上传?
问题根源
原生<input type="file">绑定的FileList对象为浏览器只读接口,本身无内置多会话文件累加逻辑:每次用户完成文件选择流程后,新的选中结果会完全替换掉之前绑定的文件列表,因此分次选择文件时,始终只会保留最后一次选中的内容,读取files.length自然也只能拿到1。
可落地方案
自定义内存文件缓存池(纯原生无依赖实现)
核心思路是绕开原生input不可修改的限制,用独立的JS数组累计所有用户分次选中的文件,不依赖input本身存储已选内容:
- 初始化全局数组
selectedFiles作为统一的文件存储容器 - 监听input的
change事件,每次用户完成文件选择,将本次获取的FileList中的所有文件追加到全局数组中 - 页面展示的已选文件列表直接基于全局数组渲染,支持单文件删除(从数组中移除对应索引元素即可)
- 发起上传请求时,将全局数组中的所有
File实例按原有表单字段名追加到FormData中提交,和原表单的提交结构完全一致
关键实现代码:
// 全局文件缓存池 let selectedFiles = []; const fileInput = document.getElementById('upload_file'); // 监听文件选择完成事件 fileInput.addEventListener('change', (e) => { // 将本次选中的文件追加到缓存,不覆盖历史内容 selectedFiles = selectedFiles.concat(Array.from(e.target.files)); // 清空input的value,避免重复选择同一文件时无法触发change事件 e.target.value = ''; // 调用渲染函数,更新页面已选文件列表 renderSelectedFileList(selectedFiles); }); // 提交上传逻辑 async function submitUpload() { const formData = new FormData(); // 按原表单字段名追加所有缓存的文件 selectedFiles.forEach(file => { formData.append('upload_file[]', file); }); // 正常发起请求提交formData即可 const uploadRes = await fetch('/upload-api', { method: 'POST', body: formData }); }
实现注意事项:
- 必须在每次change事件触发后清空input的value,否则用户两次选择同一路径下的同一文件时,因为input值无变化,不会触发change事件,会漏选文件
- 不要尝试直接修改input的
files属性,该属性为浏览器暴露的只读接口,手动赋值会抛出权限报错
成熟组件复用
如果不想手动维护缓存逻辑,可以直接选用内置多文件累加能力的上传类组件,这类组件默认已经实现了文件累计、已选列表管理、批量上传的能力,不需要从零开发。
内容的提问来源于stack exchange,提问作者ASCll
相关产品推荐
相关产品推荐

