必须在 choose 回调中保存文件总大小,并在 before 回调中 return false 启用手动上传模式,progress 回调才能触发;再通过 totalsize × n / 100 计算已上传字节数并转为 mb/kb 显示,多文件需隔离每个文件的 totalsize 避免覆盖。
progress 回调里拿不到已上传字节数?必须手动计算
layui 的 progress 回调只提供百分比 n,不暴露原始字节数。想显示“已上传 12.4 mb / 48.2 mb”,得自己算——核心是把 obj.files[0].size(总字节数)和当前进度百分比结合,推导出已传字节数。
常见错误是试图从 obj 或 xhr 对象里直接读 loaded 字段:layui 封装后不透出原生 XMLHttpRequest.upload.onprogress 的 event.loaded 和 event.total,你拿不到原始事件对象。
- 必须在
choose回调里先存下总大小:var totalSize = obj.files[0].size -
progress回调中用Math.round(totalSize * n / 100)算已上传字节数 - 转成 MB 要除以
1024 * 1024,保留一位小数:(bytes / 1048576).toFixed(1) - 多文件场景下,每个文件需独立维护
totalSize,不能复用同一个变量
为什么 before 中 return false 是硬性前提
不写 return false,progress 回调根本不会触发——layui 只有在「手动上传模式」下才启用进度监听链。自动上传走的是简化路径,跳过所有进度相关逻辑。
这和是否配置 auto: false 无关,关键在 before 函数的返回值。漏掉这句,你看到的永远是静默上传,progress 形同虚设。
-
before: function(obj){ /* 不写 return false */ }→ 进度回调永不执行 -
before: function(obj){ return false; }→ 进入手动流程,progress可用 - 即使写了
auto: false,没return false也白搭 - 别在
before里做异步操作(如校验),它必须同步返回false
显示格式容易踩的坑:KB/MB 单位混淆与精度丢失
用户选了个 2.1 MB 文件,进度走到 50% 时显示“1.0 MB / 2.1 MB”看起来合理,但实际已传字节数是 2100000 * 0.5 = 1050000,换算成 MB 是 1050000 / 1048576 ≈ 1.001,四舍五入后还是 1.0 —— 这没问题;但若用 KB 显示,1050000 / 1024 ≈ 1025.4,和总大小 2100000 / 1024 ≈ 2050.8 相除,百分比会轻微漂移。
- 统一用字节做中间计算,避免多次转换单位引入误差
- 显示时优先用 MB(大文件),KB(小文件)可按阈值切换:
totalSize > 1048576 ? 'MB' : 'KB' -
toFixed(1)在 JS 中对0.05会变成"0.1",但对0.049999999999999996仍是"0.0",别依赖它做精确比较 - 不要用
parseInt截断,它会丢精度;用Math.floor或Math.round更可控
多文件上传时字节数显示要隔离作用域
多个文件共用同一个 progress 回调,但每个文件的 totalSize 和当前进度互不影响。如果你把 totalSize 存在闭包外层变量里,后一个文件会覆盖前一个,导致进度数值错乱。
典型错误写法:var totalSize; choose(){ totalSize = obj.files[0].size; } progress(){ console.log(totalSize); } —— 第二个文件选中后,第一个文件的 progress 里读到的就是第二个文件的大小。
- 正确做法:在
choose里为每个文件生成唯一 key(如时间戳 + index),存进 Map 或对象 - 或直接把
totalSize作为参数传入后续逻辑:obj.upload({ totalSize: obj.files[0].size }),再在progress中通过this或闭包捕获 - 更稳妥的是在
choose中为每个文件动态创建 DOM 节点,并把totalSize存在data-属性里,progress通过event.target反查 - 别用全局变量或
layui.cache存,它们不是为并发文件设计的
真实字节数显示依赖前端计算精度和浏览器上报粒度,IE11 及以下可能上报不连续,Chrome/Firefox 一般每 1–2% 触发一次 progress。别指望它实时到毫秒级,只要用户能感知上传在动,就达到了目的。











