关键在multiple属性:不加只能单选,加上才支持多选;单选写<input type="file" name="avatar">,多选写<input type="file" name="attachments" multiple>,注意是multiple而非multiples。

如何用 <input type="file"> 实现单选和多选?
关键在 multiples 属性是否存在,而不是靠 JS 模拟或隐藏域“骗”浏览器。没有该属性,默认只能选一个文件;加上它,用户才能按住 Ctrl(Windows)或 Cmd(macOS)多选,或直接框选多个文件。
注意:multiples 是布尔属性,写成 multiples 或 multiples="" 效果一样,但不要写 multiples="false"——这反而会触发多选(HTML 中布尔属性只要存在即为 true)。
- 单选:
<input type="file" name="avatar"> - 多选:
<input type="file" name="attachments" multiples> - 限制类型(如只允许图片):
<input type="file" accept="image/*">,但注意accept仅过滤文件选择对话框,不能替代服务端校验 - 限制数量(需 JS 配合):
<input type="file" multiples>后监听change事件,检查e.target.files.length是否超限
input[type="file"] 的 files 对象怎么取?
e.target.files 是一个 FileList 对象,不是数组,不能直接用 map 或 forEach。常见误操作是写 Array.from(e.target.files).forEach(...),虽然能跑通,但没必要——现代浏览器支持 for...of 直接遍历,更轻量。
每个 File 实例有 name、size、type、lastModified 等属性,可用于前端预检(比如拒绝 >100MB 的文件)。
input.addEventListener('change', e => {
const files = e.target.files;
for (const file of files) {
if (file.size > 100 * 1024 * 1024) {
alert(`${file.name} 超过 100MB,已跳过`);
continue;
}
// 这里可 push 到 FormData 或做 FileReader 读取
}
});上传时为什么后端收不到多个文件?
根本原因常出在 FormData 构造方式:如果用 formData.append('file', file) 循环追加,且字段名相同(如都叫 file),PHP/Node.js 等后端默认只取第一个;而 Python Flask 的 request.files.getlist('file') 才能拿到全部——前提是前端确实以同名多次提交。
所以关键不是“能不能选多个”,而是“有没有让每个文件都作为独立条目进 FormData”。正确做法是:
- 多文件上传必须用循环
append,且 key 名一致(如'files'),不要带索引(如'files[0]') - 确保后端接口明确支持同名多值解析(例如 Express 需用
multer的array('files'),而非single()) - 避免把整个
FileList直接 append:formData.append('files', files)是错的——files是对象,不是 Blob
移动端 iOS Safari 多选支持差,怎么办?
iOS 16.4 之前,<input type="file" multiples> 在 Safari 中基本无效,用户点一次只能选一个文件,且不支持长按多选。这不是 bug,是苹果早期的安全策略限制。
目前(iOS 17+)已支持,但大量用户仍卡在旧系统。如果业务强依赖多选,得降级处理:
- 改用多次单选 + “添加更多”按钮,每次选完 append 到本地列表,最后统一上传
- 用
webkitdirectory(仅 Chrome / Edge 支持)让用户选整个文件夹,但 iOS 完全不支持 - 放弃纯前端方案,接入第三方 SDK(如 Uppy)并启用其 fallback iframe 上传逻辑
最易被忽略的是:开发时用 Chrome 测试完美,上线后客服反馈“iPhone 用户总说传不了多个”,却没在真机 iOS Safari 上验证过 files.length ——这种兼容性断层,往往要等灰度放量才暴露。

















