唯一能100%获取原始文件名的时机是choose回调中遍历obj.files[i].name;file.name恒为纯文件名(如"report.pdf"),file.path始终undefined,因现代浏览器强制禁止暴露真实路径,仅可靠元数据包括name、size、type和lastModified。

choose 回调里直接取 obj.files[i].name
这是唯一能 100% 拿到原始文件名的时机。浏览器出于安全限制,file.name 永远只返回不含路径的纯文件名(如 "report.pdf"),但这个值是真实、未被重命名、未被服务端干扰的——它来自用户点击“打开”后操作系统交给浏览器的原始 File 对象。
常见错误是误用 obj.preview() 或 obj.pushFile():
-
obj.preview()的file参数在大文件或某些安卓 WebView 下可能为空或丢失name,不可靠 -
obj.pushFile()返回的是 layui 内部队列 ID 映射对象,不是原生File实例,它的name字段是后期补的,多选时顺序还可能错乱 -
before和done回调里obj.files已为空或根本不存在,拿不到任何本地元信息
多文件场景下遍历 obj.files,别信 obj.elem.files
用户一次选了 3 个文件,obj.files 就是长度为 3 的标准 FileList,每个项都有 name、size、type。而 obj.elem 是 layui 封装后的 DOM 元素,它的 files 属性在选择后已被清空(Layui 2.9+ 行为),读出来是空列表。
正确写法示例:
choose: function(obj) {
// ✅ 安全:遍历原始 FileList
Array.from(obj.files).forEach((file, i) => {
console.log('第 ' + (i+1) + ' 个文件名:', file.name);
console.log('大小:', (file.size / 1024).toFixed(1) + 'KB');
});
// ❌ 危险:obj.elem.files 已为空
// console.log(obj.elem.files[0]?.name); // undefined
}
为什么 file.path 总是 undefined?
这不是 bug,是所有现代浏览器(Chrome/Firefox/Safari/Edge)的强制安全策略。所谓 "C:\fakepath\xxx.jpg" 是旧版 IE 的遗留行为,2026 年已全面移除。DevTools 里看到的 path 字段只是调试视图模拟,实际代码中访问 file.path 或 file.webkitRelativePath 都会返回 undefined 或空字符串。
真正能稳定读取的只有:
-
file.name—— 纯文件名(必有) -
file.size—— 字节数(必有) -
file.type—— MIME 类型(可能为空,比如 .txt 文件) -
file.lastModified—— 时间戳(毫秒数,不是字符串)
连续选同一个文件不触发 choose 怎么办?
这是 input[type=file] 的原生行为:如果两次选的是完全相同的文件(路径+内容),浏览器不会再次触发 change 事件,layui 的 choose 自然也不会执行。
绕过方法是在每次渲染 upload 前清空 input 的 value:
var uploadInst = upload.render({
elem: '#test',
url: '/upload/',
choose: function(obj) {
// 正常处理 obj.files
}
});
// 在需要重选前手动清空
document.getElementById('test').value = '';
更稳妥的做法是:把上传按钮和 file input 分离,用隐藏 input + 自定义按钮触发 click,每次点击都先清空再调用 click()。
容易被忽略的一点是:有人在 preview 回调里做文件名校验,结果大文件加载失败时回调不执行,名字就丢了。要名字,永远只信 obj.files[i].name,别的都是备用方案。











