文件上传数量限制必须通过JavaScript在change事件中重置input.value来实现,同时维护独立的selectedFiles数组用于预览与删除,并在提交前二次校验,所有入口(change、drag drop等)需统一校验逻辑。

input type="file" 本身不支持 max-files 或类似属性,限制上传数量必须靠 JavaScript 在 change 事件中实时拦截和清理 —— 否则用户仍可绕过 UI 逻辑,直接调用 FormData.append() 提交任意数量文件。
监听 change 事件并清空超限选择
这是最基础也最关键的拦截点。浏览器在用户选完文件后才触发 change,此时 e.target.files 是只读的 FileList,无法删减,唯一可靠方式是重置 input.value。
- 设定上限(如 5 个),立即检查
e.target.files.length - 超限时执行
this.value = '',否则残留的files仍可能被后续代码误用 - 不要只靠
alert()提示:用户可能忽略,且移动端 alert 阻塞体验差;建议同步更新 UI 状态(如禁用提交按钮、显示红字提示) - 注意:
input.value = ''不会触发新的change事件,不会造成死循环
维护独立的 files 列表用于预览和删除
仅靠原生 input.files 无法支持“选 6 个 → 删掉 2 个 → 传剩余 4 个”这种交互,必须用 JS 维护一个可变数组(如 selectedFiles = [])。
- 每次
change触发时,把新选的File逐个 push 进数组,同时检查总长度是否 ≤ 上限 - 超出时,只取前 N 个(
selectedFiles = selectedFiles.slice(0, 5)),丢弃新增的超额部分 - 为每个文件生成预览项(如
img标签或文件名 + 删除按钮),点击删除就从数组里splice()对应索引 - 最终上传时,用这个数组构造
FormData,而不是读input.files
提交前再次校验 FormData 中的文件数
前端任何 UI 层限制都可能被跳过(比如用户直接写 JS 调用 fetch),服务端校验是底线,但前端二次确认能避免无谓请求失败。
立即学习“前端免费学习笔记(深入)”;
- 在
submit或上传函数开头,检查selectedFiles.length是否合规 - 若不合规,阻止默认行为,并聚焦到文件输入框或高亮错误区域
- 避免只依赖
input.files.length—— 它可能和你维护的列表不一致(例如用户手动修改了 input 元素) - 如果用了拖拽上传(
drop事件),同样要走同一套校验逻辑,不能只守change
真正容易被忽略的是「多入口一致性」:change、drag & drop、甚至通过 ref.click() 模拟点击触发的选择,都得走同一套文件收集 + 校验 + 存储逻辑。否则某个路径漏掉校验,限制就形同虚设。



















