使用可触发文件夹选择,但仅chromium系浏览器支持;选中后files为扁平化文件列表,路径信息需通过file.webkitrelativepath获取,不递归子目录,无跨浏览器标准方案。

file input 怎么选中整个文件夹
用 webkitdirectory 属性即可触发文件夹选择,但仅限 Chromium 系统(Chrome、Edge、新版 Opera),Firefox 和 Safari 不支持。HTML 层面没有跨浏览器的标准方案。
写法是:<input type="file" webkitdirectory directory multiple>。其中 directory 是遗留属性(已废弃但部分浏览器仍识别),multiple 允许一次选多个文件夹,webkitdirectory 才是真正起效的属性。
- 选中后,
input.files返回的是该文件夹下所有**文件**的File列表(不含子文件夹结构) - 文件路径信息被浏览器屏蔽,无法获取原始绝对路径,只能通过
file.webkitRelativePath拿到相对于文件夹根目录的路径(如"docs/report.pdf") - 不支持递归遍历子文件夹——如果用户选了带嵌套子目录的文件夹,
input.files里只包含顶层文件,子目录里的文件不会自动展开
服务端怎么区分文件来自哪个子文件夹
靠 file.webkitRelativePath。这个字段在 Chrome/Edge 中稳定可用,值形如 "images/logo.png" 或 "data/config.json",空字符串表示文件就在所选文件夹根目录。
服务端收到每个文件时,应把这个路径作为元数据一并保存,而不是只存文件名。否则所有 logo.png 都会冲突覆盖。
- Node.js + Multer 示例:在
fileFilter或storage.filename回调里读req.file.originalname不够,得从req的原始multipart流中解析出该字段(需用busboy或自定义中间件) - Flask 中,
request.files不直接暴露webkitRelativePath,需在前端用FormData.append("path", file.webkitRelativePath)单独传一个字段 - 别依赖
file.name做唯一标识——不同子文件夹下同名文件会撞车
为什么上传文件夹后服务端收不到任何文件
常见原因不是代码逻辑错,而是漏掉关键约束条件:
-
enctype="multipart/form-data"没设在<form></form>上——这是最常踩的坑,没它,浏览器根本不会发送二进制内容 - 没加
multiple属性——即使有webkitdirectory,不加multiple时input.files.length永远是 1(只返回第一个文件) - 用了
event.preventDefault()却没手动收集input.files并构造FormData——表单 submit 被阻止后,原生上传逻辑就断了 - 移动端(尤其是 iOS Safari)完全无视
webkitdirectory,此时应降级为单文件选择 + 提示“请逐个上传”
有没有真正跨浏览器的文件夹上传方案
没有。HTML 标准至今未定义文件夹选择 API,webkitdirectory 是事实标准但非规范,Firefox 曾短暂支持后又移除,Safari 从未实现。
生产环境要兼顾兼容性,只能放弃“一次选整个文件夹”的交互,改用以下组合策略:
- 前端显示“拖拽区域”,监听
drop事件,用dataTransfer.items遍历getAsEntry()(Chrome/Edge 支持,Firefox 仅支持文件,Safari 不支持) - 对不支持的浏览器,回退到
<input type="file" multiple>+ 明确提示“可按住 Ctrl/Cmd 多选文件” - 服务端统一按“扁平文件列表”处理,把路径信息作为业务字段接收,不强求还原目录树
真正的难点不在 HTML 层,而在于你是否愿意为小众浏览器写三套上传逻辑——多数项目到这一步就决定只保 Chrome/Edge 了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











