如何在多文件上传中动态移除已选文件并更新预览列表

15次阅读

如何在多文件上传中动态移除已选文件并更新预览列表

html 文件输入框的 `files` 属性是只读的 filelist 对象,无法直接修改;需通过维护独立的文件数组(如 `selectedfiles`)来实现添加、删除与上传控制。

前端多文件上传场景中,常见的需求是:用户选择多个文件后,页面展示预览列表,并支持逐个删除某项——但直接操作 的 files 属性(如 splice() 或 delete无效,因为 input.files 是只读的 FileList 对象,任何对其的修改都不会反映到 dom 或后续上传逻辑中。

✅ 正确做法是:绕过直接修改 input.files,转而用 javaScript 维护一个可变的 File[] 数组(例如 selectedFiles = []),所有 ui 渲染、删除、上传均基于该数组操作。 仅用于初始文件选取,之后不再依赖其 files 属性。

✅ 推荐实现步骤

  1. 监听 change 事件,将新选文件追加至 selectedFiles 数组(避免覆盖,支持多次选择);
  2. 构建文件预览列表(含删除按钮),每个按钮绑定对应索引的 removeFile(index)
  3. removeFile(index) 从 selectedFiles 中移除指定项,并重新渲染列表;
  4. 上传时遍历 selectedFiles 构造 FormData,而非读取 input.files。

? 完整示例代码

   

暂无文件

let selectedFiles = [];  document.getElementById('fileInput').addEventListener('change', function (e) {   if (e.target.files.length === 0) return;    // 将新选文件合并进数组(避免重复引用问题)   selectedFiles = [...selectedFiles, ...Array.from(e.target.files)];   displayFiles();   document.getElementById('uploadBtn').disabled = false; });  function displayFiles() {   const listEl = document.getElementById('fileList');   if (selectedFiles.length === 0) {     listEl.innerhtml = '

暂无文件

'; return; } listEl.innerHTML = selectedFiles.map((file, idx) => `
? ${file.name} (${(file.size / 1024).toFixed(1)} KB)
`).join(''); } function removeFile(index) { selectedFiles.splice(index, 1); displayFiles(); // 若删空,则禁用上传按钮 if (selectedFiles.length === 0) { document.getElementById('uploadBtn').disabled = true; } } document.getElementById('uploadBtn').addEventListener('click', async function () { if (selectedFiles.length === 0) return; const formData = new FormData(); selectedFiles.forEach(file => { formData.append('files[]', file, file.name); // 第三个参数确保原始文件名 }); try { const res = await fetch('/upload', { method: 'POST', body: formData }); alert(`上传成功!共 ${selectedFiles.length} 个文件。`); selectedFiles = []; // 重置 displayFiles(); } catch (err) { console.error('上传失败:', err); alert('上传出错,请检查网络或服务器状态。'); } });

⚠️ 注意事项

  • ❌ 不要尝试 input.files.splice() 或 delete input.files[i] —— 这些操作静默失败,FileList 不可变;
  • ✅ 使用 Array.from(input.files) 仅用于一次性读取快照,后续所有操作必须基于你自己的数组;
  • ? 上传时若需保留原始文件名,务必在 formData.append() 中显式传入第三个参数(file.name),否则服务端可能收到临时名;
  • ? 如需支持拖拽上传、校验(大小/类型)、进度条等,可在 selectedFiles 管理基础上扩展,保持逻辑解耦。

通过这种「数据驱动 UI」的方式,你不仅能可靠地增删文件,还能轻松集成校验、排序、分组等高级功能,是现代文件上传交互的最佳实践。

text=ZqhQzanResources