必须用 shade: false 配合 pointerevents='none'、键盘拦截和 ios ontouchstart 兜底,否则遮罩无效;shade: 0 仅视觉隐藏却移除底层锁定,导致可交互。
直接结论:用 shade: 0 不够,必须配合 document.body.style.pointerevents = 'none' + 键盘拦截 + ios 特殊兜底,否则“没遮罩但锁不住”是常态。
为什么 shade: 0 不能直接禁用背景操作
Layui 的 shade: 0 是“视觉隐藏”,但会主动移除对 body 的 pointer-events: none 锁定和 overflow: hidden 限制——它不是“保留功能只藏样式”,而是“删掉锁,再把遮罩变透明”。结果就是:遮罩 DOM 还在(占位、挡事件),但底层已可点可输。真正要的是“无遮罩 DOM + 底层锁死”,所以得手动补上行为控制。
完整可靠写法(含 iOS 兜底)
以下配置在 Layui 2.9.13+ 真机实测有效:
layer.msg('操作中,请稍候', {
icon: 16,
shade: false, // 推荐用 false 而非 0:彻底不生成 .layui-layer-shade 元素,避免 iOS 触摸穿透
time: 2000,
success: function(layero) {
document.body.style.pointerEvents = 'none';
// 拦截 Esc / Tab 防焦点逃逸
layero.onkeydown = function(e) {
if (e.key === 'Escape' || e.key === 'Tab') e.preventDefault();
};
// iOS Safari 对 input/select 的 pointer-events: none 失效,需额外阻止
document.querySelectorAll('input, select, textarea').forEach(el => {
el.setAttribute('ontouchstart', 'event.preventDefault()');
});
},
end: function() {
// 延迟恢复,避开关闭动画抢事件窗口(约 200ms)
setTimeout(() => {
document.body.style.pointerEvents = '';
document.querySelectorAll('input, select, textarea').forEach(el => {
el.removeAttribute('ontouchstart');
});
}, 200);
}
});
常见翻车点和对应处理
-
shade: 0和shade: false混用:前者留 DOM 占位,后者更干净;移动端一律选false - 没清
ontouchstart:iOS 下用户快速连点 input,仍可能唤起软键盘 -
end回调里没加setTimeout:弹层动画未结束时 body 已恢复可点,用户点中底层按钮 - 页面有 fixed 导航栏或全局 modal:它们可能独立于 body 锁定逻辑之外,需单独对其加
pointer-events: none
真正难的不是写几行代码,而是让“看不见的锁”在各种设备、各种嵌套层级、各种用户手速下都稳住——尤其是 iOS 上那些不听 pointer-events 的表单控件,得靠 ontouchstart 强制按住。











