如何实现input type file多批次叠加选择不同目录文件?
实现文件叠加选择的纯JS方案
你遇到的问题是浏览器原生input[type=file]的默认行为:每次打开文件选择框并选择新文件时,会覆盖之前选中的文件列表。这是因为input的files属性是只读的FileList对象,无法直接向其中添加新文件。不过我们可以用纯JavaScript来实现“叠加选择”的效果,核心思路是用一个数组缓存所有选中的文件,提交时再统一处理。
具体实现步骤
1. 基础HTML结构
先准备好文件选择器、提交按钮和可选的文件列表展示区:
<input type="file" id="fileInput" multiple> <button id="submitBtn">提交所有文件</button> <!-- 用于展示已选文件的列表 --> <ul id="selectedFilesList"></ul>
2. JavaScript逻辑实现
我们需要用数组缓存已选文件,监听选择事件来更新缓存,最后提交时用FormData打包所有文件:
// 用于缓存所有选中文件的数组 let allSelectedFiles = []; // 获取DOM元素 const fileInput = document.getElementById('fileInput'); const submitBtn = document.getElementById('submitBtn'); const fileListElement = document.getElementById('selectedFilesList'); // 监听文件选择事件 fileInput.addEventListener('change', (e) => { // 将新选中的FileList转换为数组 const newFiles = Array.from(e.target.files); // 把新文件添加到缓存数组(可选:这里可以加去重逻辑) allSelectedFiles = [...allSelectedFiles, ...newFiles]; // 更新页面上的文件展示列表 renderFileList(); }); // 渲染已选文件列表到页面 function renderFileList() { fileListElement.innerHTML = ''; allSelectedFiles.forEach((file, index) => { const listItem = document.createElement('li'); listItem.textContent = `${file.name} (${formatFileSize(file.size)})`; // 可选:添加删除单个文件的功能 const deleteBtn = document.createElement('button'); deleteBtn.textContent = '删除'; deleteBtn.style.marginLeft = '10px'; deleteBtn.addEventListener('click', () => { allSelectedFiles.splice(index, 1); renderFileList(); }); listItem.appendChild(deleteBtn); fileListElement.appendChild(listItem); }); } // 辅助函数:格式化文件大小为易读格式 function formatFileSize(sizeInBytes) { if (sizeInBytes < 1024) return `${sizeInBytes} B`; if (sizeInBytes < 1024 ** 2) return `${(sizeInBytes / 1024).toFixed(2)} KB`; return `${(sizeInBytes / (1024 ** 2)).toFixed(2)} MB`; } // 处理文件提交 submitBtn.addEventListener('click', () => { if (allSelectedFiles.length === 0) { alert('请先选择至少一个文件'); return; } // 创建FormData对象,用于发送文件 const formData = new FormData(); // 将所有缓存的文件添加到FormData allSelectedFiles.forEach(file => { formData.append('uploadedFiles[]', file); }); // 发送上传请求(这里用fetch,你也可以换成XMLHttpRequest) fetch('/your-upload-api-endpoint', { method: 'POST', body: formData }) .then(response => response.json()) .then(result => { console.log('文件上传成功:', result); // 上传成功后重置状态 allSelectedFiles = []; renderFileList(); fileInput.value = ''; // 重置input,方便下次选择 }) .catch(error => { console.error('文件上传失败:', error); }); });
关键说明
- 为什么不能直接修改input的files?:浏览器出于安全考虑,
FileList对象是只读的,无法直接修改或添加内容,所以必须用数组来缓存文件。 - 可选优化:如果需要避免重复选择同一个文件,可以在添加新文件时加入去重逻辑,通过文件的
name、size和lastModified来判断是否重复。 - 用户体验:自定义的文件列表展示可以让用户清晰看到所有已选文件,还能添加删除功能,比原生input的默认提示更友好。
内容的提问来源于stack exchange,提问作者Hanish Vashishtha
相关产品推荐
相关产品推荐

