layui 的 choose 回调是唯一能同步获取原始 file 对象的时机,此时 obj.files 是标准 filelist,可安全遍历并用 filereader.readasdataurl() 生成 base64 预览;需设 auto: false 并手动触发上传。
choose 回调是唯一能同步拿到 file 对象的地方
用户点选文件后,layui 的 choose 回调是**唯一能直接访问原始 file 实例**的时机。此时 obj.files 是标准 filelist,obj.files[0] 就是你要预览的文件(单图)或需遍历的起点(多图)。before 里 obj 不带 files,done 里只返回服务器响应,preview 回调则仅限图片、兼容性差且不传真实 file 对象。
常见错误包括:
- 在
done里试图用res.data.url更新预览——用户早已完成选择,却要等上传完才看到图,体验断档 - 误以为
obj.preview()是通用入口,结果在安卓 WebView 或非图片类型下静默失败 - 写成
obj.file.size(属性不存在)或读取obj.elem.files[0](Layui 已接管 DOM input,该值为空)
用 FileReader.readAsDataURL() 生成可嵌入的预览地址
FileReader.readAsDataURL() 是目前最稳妥的多图预览方式:它把文件转为 base64 字符串,可直接赋给 <img src>,不依赖后端、无跨域限制、兼容性覆盖 IE10+ 和所有现代浏览器。
实操要点:
- 先过滤非图片:
/^image\//.test(file.type),跳过 PDF、TXT 等类型 - 用
Array.from(obj.files)转换FileList为数组,再forEach遍历,避免闭包导致所有<img>显示同一张图 - 每个
FileReader实例必须独立创建,onload中用reader.result设置img.src - 预览容器(如
<div id="preview-box"></div>)在choose开头清空,防止残留旧图
示例片段(放在 choose 回调内):
Array.from(obj.files).forEach((file, i) => {
if (!/^image\//.test(file.type)) return;
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const img = document.createElement('img');
img.src = reader.result;
img.style.maxWidth = '120px';
img.style.margin = '4px';
img.setAttribute('data-index', i);
document.getElementById('preview-box').appendChild(img);
};
});
auto: false 是预览可控的前提
如果 auto: true(默认),用户一选完文件,上传立刻触发,choose 回调里刚生成预览,请求可能已发出甚至失败,用户根本来不及确认图片是否正确。更糟的是,上传失败后页面还留着旧预览,造成误导。
必须显式设 auto: false,并配合一个独立的“确认上传”按钮(如 bindAction: '#upload-btn'),确保预览完成后再手动调用 obj.upload()。
其他关键动作:
- 在
choose开头清空预览区:document.getElementById('preview-box').innerHTML = '' - 在
error或interrupt回调中也清空一次,避免失败状态残留 - 不要在
choose末尾自动调obj.upload(),否则失去控制权
预览图模糊、拉伸、一闪而过?查 DOM 和样式
这些问题往往和代码逻辑无关,而是由 DOM 结构或 CSS 导致:
-
<img>没设max-width: 100%或height: auto,导致大图撑开布局或变形 - 容器(如
#preview-box)没设display: flex或overflow: hidden,缩略图溢出或换行错乱 - 用户选了超大图(如 15MB PNG),
FileReader读取卡顿甚至阻塞主线程,建议前端加大小限制(如if (file.size > 5 * 1024 * 1024))并提示 - 未捕获
FileReader.onerror,读取失败时没降级显示占位符或文件名,用户看到空白
Canvas 压缩缩略图不是必须项,但若业务明确要求统一尺寸(如全部 120×120),就得在 onload 后用 canvas 绘制再转 dataURL——那已是另一层复杂度,别在基础预览阶段强加。











