必须在choose回调中用obj.resetFile()替换文件才能生效,因Layui仅在此阶段暴露可写索引且auto:true会跳过所有修改;before中改files无效,未调resetFile则上传仍为原图。

必须在 choose 回调里压缩,禁用 auto: true,否则后端收到的一定是未压缩原图——这是唯一能生效的路径。
为什么只能在 choose 里操作
Layui 的 upload 模块只在 choose 阶段暴露原始 File 列表,并允许调用 obj.resetFile(index, blob, filename) 替换文件;before 阶段拿不到可写入的索引,也无法重置;开启 auto: true 时会跳过所有你对文件对象的修改,直接发原始文件。
常见错误现象:
- 在
before里改obj.files[0] = compressedBlob→ 后端仍收大图 - 没关
auto,只在choose里调resetFile→ 压缩被忽略,上传自动触发 - 用
for...in遍历files后直接obj.upload(index, file)→ 顺序错乱、部分文件丢失
如何用 canvas 正确压缩并塞回上传队列
核心不是“生成新 Blob”,而是必须通过 obj.resetFile() 显式写入,Layui 不监听 files 对象的任何内存变更。
实操要点:
- 先用
obj.pushFile()获取待上传文件集合,它是 plain object(非数组),键是内部 index 字符串 - 检查
file.type是否为image/jpeg或image/png,否则canvas.toDataURL('image/jpeg', 0.7)可能返回空字符串 - quality 推荐设为
0.7~0.85:低于0.6模糊明显,高于0.9体积下降不明显 - 原图宽高超
4096px时,部分安卓 WebView 会崩溃,建议等比缩放到maxWidth: 2000 -
filename必须保留原扩展名(如"photo.jpg"),否则后端可能因Content-Type识别错误而拒收
多图并发压缩与上传控制
choose 是同步回调,但图片压缩是异步过程。不能在循环中立即调 obj.upload(),否则上传时机不可控。
正确做法:
- 用
Object.keys(files)得到安全索引数组,避免for...in顺序问题 - 对每个文件调用压缩函数,返回 Promise,收集进
promises数组 - 统一
Promise.all(promises).then(() => { /* 批量 obj.upload() */ }) - 任一压缩失败时,fallback 到
obj.upload(index, files[index])上传原图,避免中断流程
最易被忽略的是:哪怕你用 URL.createObjectURL() 或 new Blob() 生成了完美压缩后的二进制,只要没调 obj.resetFile(),obj.upload() 发出去的仍是原始 File 对象——Layui 只认它自己维护的那一份。











