关键属性是multiple,添加后可多选文件;需配合enctype="multipart/form-data"、后端正确解析数组(如express用upload.array()、php遍历$_files'files'),并注意ios 16.4以下不支持。

HTML 表单怎么让 <input type="file"> 支持选多个文件
关键就一个属性:multiple。没有它,用户点一次只能选一个文件;加了它,按住 Ctrl(Windows)或 Cmd(macOS)可多选,或者直接框选,甚至拖拽多个文件进来都生效。
常见错误是只写 <input type="file"> 却忘了加 multiple,结果测试时总以为是浏览器限制或 JS 问题。
-
<input type="file" name="files" multiple>—— 必须带multiple,否则后端收不到多个File对象 - name 属性建议用复数形式(如
files),方便后端识别是数组型字段(尤其在 PHP、Node.js 的 form-data 解析中) - 别依赖
accept来“限制”上传数量,它只过滤类型,不影响多选能力
后端接收时为什么只拿到第一个文件
不是前端没传全,大概率是后端解析逻辑把 files 当成单值处理了。比如用 req.file(Express 默认单文件中间件)而不是 req.files,或 PHP 的 $_FILES['files'] 结构没展开遍历。
files 字段在 multipart/form-data 中实际是数组结构:每个文件对应一组 name、tmp_name、size 等键,但 PHP 把它们平铺在同级数组里,Node.js 的 multer 则默认需显式指定 .array('files') 才能正确提取。
立即学习“前端免费学习笔记(深入)”;
一套面向小企业用户的企业网站程序!功能简单,操作简单。实现了小企业网站的很多实用的功能,如文章新闻模块、图片展示、产品列表以及小型的下载功能,还同时增加了邮件订阅等相应模块。公告,友情链接等这些通用功能本程序也同样都集成了!同时本程序引入了模块功能,只要在系统默认模板上创建模块,可以在任何一个语言环境(或任意风格)的适当位置进行使用!
- Express + multer:用
upload.array('files'),不是upload.single() - PHP:遍历
$_FILES['files']['name']数组,逐个取$_FILES['files']['tmp_name'][$i] - 注意:如果表单里还有其他
input字段,它们的值不会丢,但必须在enctype="multipart/form-data"下才能和文件一起提交
JavaScript 怎么读取多个文件并预览
用户选完后,input.files 是一个 FileList 对象,不是数组,所以不能直接用 map 或 forEach,得先转成数组或用 for 循环。
容易踩的坑是直接对 input.files 调 .forEach(),报错 “not a function”。另一个坑是用 URL.createObjectURL() 后没及时 revoke,导致内存泄漏,尤其在频繁操作预览时。
- 安全读取:
Array.from(input.files).forEach(file => { ... }) - 预览图片:对每个
file创建new FileReader(),监听load后赋值给<img src alt="HTML表单如何实现多文件上传_HTML表单实现多文件上传方法【操作】" > - 大文件别一次性读进内存,用
file.slice()分块或直接上传,避免卡顿
移动端 iOS Safari 多文件上传为什么失效
iOS 16.4 之前,Safari 的 <input type="file" multiple> 实际只支持单选——它会忽略 multiple,且不报错。用户点了还是只能选一个,开发者查 console 也看不出问题。
这不是代码写错了,是系统限制。iOS 16.4+ 才真正支持,但很多用户还没升级。如果你的业务必须支持旧版 iOS,就得换方案:比如用多个单文件 input,或改用 WebKit 兼容的第三方库(如 fine-uploader 的降级逻辑)。
- 检测方式:
input.multiple === true && 'files' in input在 iOS 16.4- 返回true,但input.files.length永远是 1 - 别信 “加
webkitdirectory就能多选”,它只对文件夹有效,且 iOS 不支持 - 真要兼容,服务端得接受多次单文件请求,前端用 Promise.all 控制并发
表单多文件上传本身不难,难的是跨浏览器行为差异、后端解析习惯、以及移动端那个藏得很深的 iOS 版本墙。最常被跳过的其实是检查 enctype 和后端接收方式是否匹配——这两处一错,前面所有 HTML 和 JS 都白搭。










