
html 文件输入框的 `files` 属性是只读的 filelist 对象,无法直接修改或删除其中某一项;正确做法是维护一个独立的文件引用数组,在上传时按需过滤,而非尝试篡改原生 input.files。
在实现多文件上传并支持“删除预览文件”功能时,一个常见误区是试图直接操作 元素的 files 属性(例如用 splice() 或 delete),但这是无效的——因为 input.files 是只读的类数组对象(FileList),任何对其的修改都不会反映到实际数据上,也不会触发 DOM 更新。
✅ 正确思路:脱离原生 files,转而维护一个可变的 JavaScript 数组(如 selectedFiles = []),并在用户选择文件后、删除操作时、上传前分别管理该数组。
✅ 推荐实现步骤
-
监听 change 事件,将 e.target.files 转为真实数组并存入变量
let selectedFiles = []; document.getElementById("fileInput").addEventListener("change", function(e) { if (e.target.files.length > 0) { selectedFiles = Array.from(e.target.files); // ✅ 可增删改的真实数组 displayFiles(); // 渲染预览列表(含删除按钮) } }); -
实现 removeFile(index):从 selectedFiles 中删除,而非操作 input.files
立即学习“前端免费学习笔记(深入)”;
function removeFile(index) { selectedFiles.splice(index, 1); // ✅ 安全删除 displayFiles(); // 重新渲染剩余文件 } -
displayFiles() 示例:生成带删除按钮的预览列表
function displayFiles() { const list = document.getElementById("fileList"); list.innerHTML = ""; selectedFiles.forEach((file, i) => { const li = document.createElement("li"); li.innerHTML = ` ${file.name} (${(file.size / 1024).toFixed(1)} KB) `; list.appendChild(li); }); } -
上传时:仅遍历 selectedFiles 数组构造 FormData
function uploadFiles() { const formData = new FormData(); selectedFiles.forEach(file => { formData.append("files[]", file); // ✅ 使用当前有效文件 }); fetch("/upload", { method: "POST", body: formData }) .then(res => res.json()) .then(console.log) .catch(console.error); }
⚠️ 注意事项
- ❌ 不要尝试 input.files.splice()、delete input.files[i] 或赋值 input.files = newArray —— 浏览器会静默忽略;
- ✅ FileList 只能读取,所有“删除”逻辑必须基于你自己的数组副本;
- 若需保留原始选择顺序或支持取消再选,可额外记录 input 的 value 或使用 DataTransfer 模拟(进阶场景);
- 在生产环境建议增加文件类型/大小校验、防重复提交、上传进度反馈等健壮性处理。
通过这种「解耦式管理」,你既能自由控制待上传文件集合,又能保持 UI 与数据状态严格同步,是现代多文件交互的标准实践。










