choose回调是唯一能同步获取原始File对象的地方,因其传入obj.files[0]为标准File实例,而done仅返回服务器响应、before未读取内容、preview仅限图片且兼容性差。
必须在 choose 回调里用 url.createobjecturl() 处理 obj.files[0],不能等 done 或依赖 preview 回调——那是上传成功后的事,预览早就该完成了。
为什么 choose 是唯一能拿到原始 File 对象的地方
choose 是 upload 模块中**唯一同步暴露用户本地选中文件**的回调。它传入的 obj 里有 files 属性,是原生 FileList,每个项都是标准 File 实例(含 name、size、type)。done 只返回服务器响应,before 还没读取文件内容,preview 回调(Layui 2.8+ 才有)只对图片生效且兼容性差。
常见错误包括:
- 只写
done回调,试图用res.data.url赋值给<img src>—— 此时用户还没看到图,体验断档 - 误以为
obj.preview()是万能预览入口,结果在安卓 WebView 或非图片类型下静默失败 - 没检查
file.type就直接生成 URL,导致点击 PDF 后<img>加载失败且无提示
怎么用 URL.createObjectURL() 安全生成预览地址
这是最轻量、最兼容的预览方式:不读取文件二进制,不转 base64,不触发跨域限制,生成的 blob: 地址可直接塞进 <img src>。
实操要点:
- 取第一个文件:
const file = obj.files[0](单图场景),并用/image\//.test(file.type)过滤 - 生成地址:
document.getElementById('preview-img').src = URL.createObjectURL(file) - 必须及时释放:
URL.revokeObjectURL()应在切换图片或组件销毁前调用,否则内存泄漏风险高(尤其频繁操作) - 别用
FileReader.readAsDataURL()—— 大图(如 5MB PNG)转 base64 后体积膨胀 33%,iOS Safari 易崩溃
auto: false 是预览可控的关键开关
如果 auto: true(默认),选完文件立刻上传,choose 回调里刚生成预览,上传就已开始,用户根本来不及看;更糟的是,若上传中途失败,页面还留着旧图,造成误导。
推荐配置:
- 显式设
auto: false - 在
choose里完成预览逻辑 - 另配一个“确认上传”按钮,点击时手动调
obj.upload() - 同时在
choose开头清空旧预览:document.getElementById('preview-img').src = '',避免残留 - 上传失败(
error或interrupt)时也清空一次
预览图显示异常的几个硬坑
预览出来模糊、拉伸、一闪而过,往往不是代码逻辑错,而是 DOM 和样式没兜住:
-
<img>标签没设max-width: 100%; height: auto;,大图直接撑爆容器 - 目标
<img id="preview-img">元素在 DOM 中不存在或 ID 拼错,getElementById返回null,赋值无效 - 用了
URL.createObjectURL()却忘了revoke,连续选 10 张图后内存占用飙升 - 用户选了超大图(20MB+),虽然
createObjectURL不卡,但渲染时浏览器主动降质或丢帧
真正难处理的,是预览和上传状态的耦合:比如用户点了“选图”,又取消,或者上传中刷新页面——blob: 地址立即失效,但 DOM 还挂着,得靠业务层主动清理,框架不替你管这个。


















