直接用layer.photos配合事件委托实现图片预览,须避开三坑:templet内联onclick失效(因表格动态渲染导致绑定丢失)、不可单独绑定事件、photos结构必须为{photos:{data:[]}};正确做法是在done回调中用layui.$对.layui-table-box委托绑定click事件,并每次先off再on防重复。

直接用 layer.photos 配合事件委托就能实现,但必须避开三个典型坑:不能在 templet 里写 onclick,不能对每张图单独绑定事件,不能传错 photos 结构。
为什么 templet 里写 onclick 会失效
Layui 表格是动态渲染的——翻页、重载、搜索后 DOM 全部重建。写在 templet 里的 onclick="showImg('{{d.avatar}}')" 本质是内联 JS,每次重新渲染都会丢掉旧绑定,新生成的 img 没有事件;更糟的是,如果用了分页或开启 page: true,首次加载后点击可能根本没反应。
- 内联 JS 会被 Layui 的 XSS 过滤策略清空,实际不执行
- 即使没被过滤,也因 DOM 重建而丢失监听
- 移动端 click 延迟或失效风险更高
正确绑定方式:done 回调 + 事件委托
必须在 table.render 的 done 回调中,用 layui.$ 对稳定父容器委托绑定,且每次先 off 再 on 防重复:
- 绑定目标选
#demo后面的.layui-table-box(不是#demo本身),否则滚动区域内的图片点不到 - 类名统一用
.layui-table-img,别用行级随机 class 或 id - 必须用
layui.$,不用原生document.querySelector或 jQuery 的$,否则无法穿透虚拟滚动 - 每次
done触发都要先解绑再重绑,避免翻页后事件叠加或丢失
done: function(res, curr, count){
var $box = layui.$('#demo').next('.layui-table-box');
$box.off('click', '.layui-table-img').on('click', '.layui-table-img', function(){
var src = this.src;
if (!src || src.indexOf('about:') === 0) return;
layer.photos({
photos: { data: [{src: src}] },
anim: 5,
shadeClose: true
});
});
}
layer.photos 单图预览必须满足的结构要求
layer.photos 不接受字符串、数组或扁平对象,只认 {photos: {data: []}} 这个嵌套结构。常见报错 Cannot read property 'length' of undefined 就是因为传了 layer.photos({src: 'xxx.jpg'}) 或 layer.photos(['xxx.jpg'])。
-
photos.data必须是数组,哪怕只有一张图也要包成[{src: 'xxx.jpg'}] -
src字段值必须是非空字符串,且能被浏览器直接加载(相对路径需确保同域或配好 CORS) - 若后端返回
null、''或about:blank,要提前过滤,否则预览层白屏 - 建议加
anim: 5(淡入)和shadeClose: true,避免默认无动画卡顿、遮罩点不关闭
多图预览怎么搞(同一行多个图片地址)
如果某行数据带多图字段(如 d.images = ['/a.jpg', '/b.jpg']),不需要额外接口,只需把数组映射为 photos.data 格式即可:
- 前端直接
obj.data.images.map(src => ({src})),前提是images是数组;如果是 JSON 字符串(如"[\"/a.jpg\",\"/b.jpg\"]"),得先JSON.parse(obj.data.images) - 不要在
templet里拼多个<img>标签,那样无法统一触发预览 - 注意:Layui 的
layer.photos不支持异步加载图列表,所有图 URL 必须一次性提供 - 如果想从当前图开始定位,可加
start: index(index 为当前图在数组中的下标)
最易忽略的是:图片地址为空、跨域失败、或 layer 模块没在 layui.use 中声明——这三处出问题时,控制台可能静默失败,预览层弹不出也不报错。


















