Layui 的 progress 回调仅提供百分比 n,不暴露 loaded/total 字节数和时间戳,因其封装 XMLHttpRequest.upload.onprogress 时过滤了原生事件参数;正确显示“已传 X MB / Y MB”需在 choose 回调中获取 obj.files[0].size 并存储,progress 中用 n 推算已传字节数再转单位。

不能直接显示上传速率,Layui 的 progress 回调只提供百分比 n,不暴露原始 loaded 和 total 字节数,也没有时间戳;想算速率就得自己记开始时间、存总大小、在每次 progress 里算差值——但浏览器不保证回调频率,结果波动大,实际意义有限。显示文件大小倒很简单,但必须在 choose 回调里读 obj.files[0].size,其他地方全不准。
为什么 progress 里拿不到 loaded / total?
Layui 封装了原生 XMLHttpRequest.upload.onprogress,把事件参数全过滤掉了,只留一个整数百分比 n。你试图从 obj、xhr 或 this 上找 loaded 或 total,一律返回 undefined。这不是 bug,是设计如此——它只做进度条驱动,不做传输监控。
- 别写
xhr.upload.loaded:Layui 没透出这个xhr实例 - 别依赖
obj.file.size:这个属性根本不存在,obj在progress里也不带files - 想“假装”有速率?只能靠
choose里记startTime = Date.now()+totalSize = obj.files[0].size,然后在progress里用(Date.now() - startTime)做分母,但首次回调可能延迟 100ms+,前几帧速率完全失真
怎么正确显示“已传 X MB / Y MB”?
核心是手动计算:用 choose 存总大小,用 progress 里的 n 推导已传字节数,再转单位。注意多文件时每个文件要独立存 totalSize,否则后一个覆盖前一个。
- 在
choose回调开头加:var totalSize = obj.files[0].size; - 在
progress回调里算:var uploadedBytes = Math.round(totalSize * n / 100); - 转 MB 显示(保留一位小数):
(uploadedBytes / 1048576).toFixed(1) + " MB / " + (totalSize / 1048576).toFixed(1) + " MB" - 如果文件小于 1MB,建议切到 KB 单位:
uploadedBytes
为什么 before 中 return false 是前提?
不写这句,progress 回调压根不会触发——Layui 只在「手动上传模式」下启用进度监听链。自动上传走的是简化路径,跳过所有进度逻辑。哪怕你写了 auto: false,只要 before 没 return false,照样静默上传。
-
before: function(obj){ /* 忘了 return false */ }→progress永远不执行 -
before: function(obj){ return false; }→ 进入手动流程,progress可用 -
before必须同步返回false,不能在里面做异步校验(比如发请求查黑名单),否则流程中断或错乱
真正难的不是算数,而是把「浏览器发了多少」「服务器收没收到」「用户看懂没」三件事对齐。比如 n === 100 只代表发完,不代表服务器已落盘;而你显示的 “48.2 MB / 48.2 MB” 看似圆满,其实后面还卡着几秒响应延迟——这点最容易被忽略。


















