choose回调是唯一能计算文件md5的时机,因其可获取file对象并分片读取;before无文件数据,done/error已失效;需用sparkmd5.arraybuffer分片计算,完成后挂载md5到obj供上传使用。
必须在 choose 回调里用 sparkmd5 计算文件内容 md5,不能依赖 before 或后端校验来防重复——因为此时文件已开始上传,前端已失去控制权。
为什么 choose 是唯一能做 MD5 校验的时机
layui 的 upload 组件在 choose 回调中才暴露原始 File 对象(obj.files[0]),而 before 回调里的 obj 不含 files,只有 upload() 和 preview() 方法。错过 choose,就再没机会读取文件二进制内容了。
-
choose:能拿到File实例 → 可分片读取 → 可调用SparkMD5计算内容哈希 -
before:只用于拦截上传动作,无文件数据 → 无法生成 MD5 -
done/error:请求已完成 → 防重复已失效
如何用 SparkMD5 在 choose 中计算文件 MD5
不能直接 new FileReader().readAsText(file),大文件会卡死;必须分片读取 + 增量追加,否则内存爆、浏览器假死。
- 使用
File.slice()切块(推荐2 * 1024 * 1024即 2MB) - 每次
fileReader.onload后调用spark.append(e.target.result) - 全部读完后调用
spark.end()获取最终 MD5 字符串 - 注意:
spark.end()调用一次后内部状态清空,不可重复调用 —— 拿到值立刻存变量或localStorage
choose: function(obj) {
const file = obj.files[0];
const spark = new SparkMD5.ArrayBuffer();
const chunkSize = 2 * 1024 * 1024;
let currentChunk = 0;
const chunks = Math.ceil(file.size / chunkSize);
const fileReader = new FileReader();
<p>fileReader.onload = function(e) {
spark.append(e.target.result);
currentChunk++;
if (currentChunk </p><p>function loadNext() {
const start = currentChunk * chunkSize;
const end = Math.min(start + chunkSize, file.size);
fileReader.readAsArrayBuffer(file.slice(start, end));
}</p><p>loadNext();
}</p>
MD5 校验失败后怎么阻止上传并清空界面
不能靠 return false 或 throw,layui 完全不识别;必须显式重置 + 提示,否则用户点“上传”按钮毫无反应,还以为成功了。
- 校验逻辑写在
choose回调内,比如查本地缓存或发请求比对已有 MD5 - 若命中重复,立即调用
obj.reset()清空已选文件(否则界面上仍显示“已选择 xxx”) - 紧接着用
layer.msg()或原生alert()提示,避免用户无感知 - 别忘了:
obj.reset()后不能再调obj.upload(),否则会静默失败
choose: function(obj) {
const file = obj.files[0];
// ... 计算 md5 得到 md5Str
if (isDuplicate(md5Str)) {
obj.reset(); // 必须!否则界面残留且后续上传无效
layer.msg('该文件已存在,禁止重复上传', {icon: 2});
return;
}
// 继续分片读取和上传流程
}
真正难的不是算 MD5,而是把分片读取、状态管理、错误边界、UI 同步这四件事在 choose 里闭环掉——漏掉任意一环,都会导致“看起来能跑,但线上必出问题”。











