
html 文件输入框的 `files` 属性是只读的 filelist 对象,无法直接修改;需通过维护独立的文件数组(如 `selectedfiles`)来实现添加、删除与上传控制。
在前端多文件上传场景中,常见的需求是:用户选择多个文件后,页面展示预览列表,并支持逐个删除某项——但直接操作 的 files 属性(如 splice() 或 delete)无效,因为 input.files 是只读的 FileList 对象,任何对其的修改都不会反映到 DOM 或后续上传逻辑中。
✅ 正确做法是:绕过直接修改 input.files,转而用 JavaScript 维护一个可变的 File[] 数组(例如 selectedFiles = []),所有 UI 渲染、删除、上传均基于该数组操作。 仅用于初始文件选取,之后不再依赖其 files 属性。
✅ 推荐实现步骤
- 监听 change 事件,将新选文件追加至 selectedFiles 数组(避免覆盖,支持多次选择);
- 构建文件预览列表(含删除按钮),每个按钮绑定对应索引的 removeFile(index);
- removeFile(index) 从 selectedFiles 中移除指定项,并重新渲染列表;
- 上传时遍历 selectedFiles 构造 FormData,而非读取 input.files。
? 完整示例代码
暂无文件
Mfkiqpl旅行社旅游线路预订程序下载升级报告:增加动态新闻功能后台添加,删除,编辑,支持UBB代码,支持上传片及文件。 增加我要入团功能散客可以自由选择加入贵社最近要出发的团队。 增加线路置顶功能置顶后的线路永远显示在最前面。 增加同行报价功能管理员在后台添加同行用户,同行用户登录后可查看贵社线路对同行的报价。同行报价在添加线路中一并添加。(感谢网友拽哥提出修改意见) 增加更多线路显示的分页功能方便大型旅行社由于线路过多而引起的部分
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」的方式,你不仅能可靠地增删文件,还能轻松集成校验、排序、分组等高级功能,是现代文件上传交互的最佳实践。










