Layui upload 默认不支持文件夹上传,仅 Chromium 内核浏览器通过手动创建带 webkitdirectory 的 input 可选中文件夹顶层文件,需遍历 files 调用 upload.start 单独上传;不支持递归、无路径信息、非跨平台,推荐压缩包上传或桌面端方案。

layui upload 本身不支持原生文件夹上传
浏览器的 <input type="file"> 元素在标准 HTML5 中对文件夹的支持非常有限:只有 Chrome / Edge(基于 Chromium)在启用 webkitdirectory 属性时能触发「选择文件夹」行为,且它只返回该文件夹下**顶层文件**(不含子目录递归),Firefox 和 Safari 完全不支持该属性。Layui 的 upload.render() 底层仍依赖这个原生 input,所以它默认根本不会响应文件夹选择。
用 webkitdirectory 启用文件夹选择(仅 Chromium 内核)
必须绕过 Layui 的 input 封装,手动创建并监听带 webkitdirectory 的 input,再调用 Layui 的上传逻辑处理每个文件。关键点:
- 不能直接给
upload.render()的elem加webkitdirectory—— Layui 会忽略或报错 - 需用
document.createElement('input')创建独立 input,设置type="file" webkitdirectory="true" directory="true" - 监听
change事件后,遍历e.target.files(注意:这里不是递归,只是当前文件夹一级的文件) - 对每个
File对象,调用upload.start({ field: 'file', files: [file] })单独上传(Layui 2.8+ 支持files数组参数)
示例片段:
const input = document.createElement('input');
input.type = 'file';
input.webkitdirectory = 'true';
input.directory = 'true';
input.multiple = true;
input.onchange = function(e) {
const files = Array.from(e.target.files);
files.forEach(file => {
layui.upload.start({
url: '/upload',
field: 'file',
files: [file], // 注意是单元素数组
before: () => console.log('上传中:', file.name),
done: (res) => console.log('完成:', res)
});
});
};
document.body.appendChild(input);
input.click(); // 触发选择
想真正递归上传子文件夹?浏览器不允许,必须换方案
HTML 标准禁止 JavaScript 访问文件系统路径或递归读取目录结构 —— 这是安全沙箱强制限制。所谓“文件夹上传”在前端永远只能是:用户手动选中多个文件(含不同子目录下的),或后端配合(如用 WebDAV、Electron、Tauri 等脱离浏览器环境)。常见折中做法:
- 引导用户按住
Ctrl/Cmd多选跨层级文件(最兼容) - 用
<input multiple>+ 拖拽区域(Layui 支持drag: true),让用户把整个文件夹拖进来(但实际仍是扁平化文件列表,无目录树信息) - 若业务强依赖目录结构,必须改用桌面客户端(Electron)或后端提供 ZIP 上传入口,由服务端解压还原
容易被忽略的坑
Layui 的 upload.start() 在批量调用时,如果不控制并发,可能触发浏览器连接数限制或后端限流。更隐蔽的问题是:
-
webkitdirectory返回的File对象没有webkitRelativePath(Chromium 已弃用),无法得知原始路径 —— 所有文件都丢失目录上下文 - 移动端(包括 iOS Safari、Android Chrome)完全不支持
webkitdirectory,该方案纯 PC 专用 - Layui 2.7 及以下版本不支持
files参数,必须升级到 2.8+ - 同一个
input元素重复触发click()会导致第二次 change 事件不触发(因文件路径未变),需每次新建 input 或清空value
真要保目录结构,别在前端硬扛 —— 压缩上传才是唯一可靠路径。


















