结论是必须在success回调中精准获取当前遮罩节点并手动绑定click事件,禁用shadeclose后自行控制抖动;不能依赖外部委托或anim参数,移动端需条件禁用抖动以防卡顿。
直接说结论:不能靠 shadeclose: false + 自定义抖动就完事。遮罩层点击事件默认会冒泡到 .layui-layer-shade,而 layui 内部对它的 click 监听是硬编码的——只要 shade 存在且 shadeclose: true,点它就会关窗;设成 false 则完全不响应,你连抖动都触发不了。必须把遮罩层“借”过来自己管。
怎么让点击遮罩层触发抖动而不是关闭
核心思路是:保留遮罩层(即 shade 不为 0),但禁用 layui 默认的关闭逻辑,再手动监听遮罩层 click 并执行抖动。关键步骤如下:
- 设置
shade: 0.3(或其他非 0 值),确保遮罩 DOM 存在且可绑定事件 - 显式设置
shadeClose: false,切断 layui 的自动关闭链路 - 在
success回调里,用$(layero).prev('.layui-layer-shade')找到遮罩元素并绑定 click - 抖动目标必须是弹层内容区(如
.layui-layer-content),不是遮罩本身 - 抖动完立刻移除 class,避免重复点击叠加动画
示例代码:
layer.open({
type: 1,
content: '<div class="my-form">表单内容</div>',
shade: 0.3,
shadeClose: false,
success: function(layero) {
const $shade = $(layero).prev('.layui-layer-shade');
$shade.on('click', function() {
const $content = $(layero).find('.layui-layer-content');
$content.addClass('shake');
setTimeout(() => $content.removeClass('shake'), 400);
});
}
});
为什么不能在 layer.open 外部用 $(document).on('click', '.layui-layer-shade', ...)
因为 layui 每次调用 layer.open() 都会动态创建新的遮罩 DOM,旧的会被销毁。外部委托监听容易绑错、漏绑或重复绑定,尤其在快速连续打开多个弹层时。必须在每次 success 里精准获取当前弹层对应的遮罩节点。
-
$(layero).prev('.layui-layer-shade')是最稳的方式:遮罩永远在弹层 DOM 的前一个兄弟位置 - 不要用
$('.layui-layer-shade').last(),多层嵌套时会取错 - 如果用了
zIndex或自定义skin,遮罩结构不变,该方式仍有效
移动端抖动要不要加?加了会不会卡
要加,但得关掉。iOS Safari 和部分安卓 WebView 对 transform: translateX() 频繁重绘优化极差,抖动动画极易卡顿甚至闪退。
- 建议用
matchMedia('(hover: none) and (pointer: coarse)')检测是否为触摸设备 - 检测为真时,跳过
addClass('shake'),只做轻微视觉反馈(比如加个border-color: #ff5722) - CSS 动画位移务必控制在 ±3px 内,持续时间 ≤ 0.3s,避免用户眩晕
真正难的不是写几行抖动代码,而是让遮罩层这个“被 layui 管着的客人”,老老实实听你指挥——它既不能消失,又不能乱关窗,还得响应你的每一次点击。稍一松手,就可能点两下关两个窗,或者抖三次停不下来。











