layer.open 的 content 无法直接套骨架屏,因其传入字符串时会立即渲染,而骨架屏需在异步加载中占位;应改用 type:1 + 自定义容器,在 success 中先展示骨架再异步加载内容并替换。
为什么 layer.open 的 content 无法直接套骨架屏?
因为 layer.open 的 content 参数若传入字符串(如 html 片段),layui 会立即插入 dom 并渲染,骨架屏还没来得及“动起来”,真实内容就已加载完成——尤其当内容是本地 html 片段或简单模板时,根本观察不到加载过程。
真正有加载延迟的场景,其实是 content 设为 URL(如 content: '/api/form')并配合 type: 2(iframe)或 type: 1 + 异步请求时。但 Layui 默认不提供“加载中骨架占位”机制,得手动接管内容容器生命周期。
用 type: 1 + 自定义 content 容器实现骨架占位
核心思路:不把真实内容直接丢给 layer.open,而是先塞一个带骨架屏的 <div>,等异步加载完成再替换内部 HTML。
-
layer.open的content设为一个空容器(如'<div id="layer-skeleton"></div>') - 在
success回调里立即渲染骨架屏(可用纯 CSS 骨架,或轻量库如skeleton-css) - 紧接着发起真实请求(
$.get/fetch),成功后用$('#layer-skeleton').html(...)替换内容 - 注意:别漏掉
skin: 'layui-layer-demo'这类自定义 class,方便写骨架样式
layer.open({
type: 1,
title: '编辑用户',
area: ['600px', '400px'],
content: '<div id="layer-skeleton" class="skeleton-loading"></div>',
success: function(layero) {
// 立即显示骨架(CSS 控制)
$('#layer-skeleton').addClass('show');
// 加载真实内容
$.get('/user/form/123').done(html => {
$('#layer-skeleton').removeClass('show').html(html);
}).fail(() => {
layer.msg('加载失败', {icon: 2});
});
}
});
如何写一个轻量、不依赖 JS 的骨架屏 CSS?
Layui 弹层默认无骨架样式,需自己补。关键是用 background-image: linear-gradient(...) 模拟闪烁效果,并确保尺寸贴合预期内容区域(比如表单行高、按钮宽度)。
- 避免用伪元素做骨架(
::before在display: flex容器里易错位) - 给骨架元素设固定
height和border-radius,匹配后续真实组件(如输入框高度 36px → 骨架也设height: 36px) - 动画用
animation: skeleton-loading 1.4s ease-in-out infinite,渐变方向从左到右更自然 - 务必加
pointer-events: none,否则骨架层会拦截点击
.skeleton-loading {
position: relative;
}
.skeleton-loading::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.4s ease-in-out infinite;
}
@keyframes skeleton-loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
type: 2(iframe)下怎么加骨架?
iframe 的 src 加载不可监听 onload 事件(跨域时会失败),且 Layui 的 layer.getChildFrame 必须等 iframe 加载完才有效。所以不能等 load,得靠定时轮询 contentDocument 是否可读。
- 先用
content: '<div class="skeleton-loading"></div>'占位 - 在
success里启动轮询:setInterval(() => { try { iframe.contentDocument.body } catch(e){} }, 200) - 一旦能取到 body,立刻移除骨架类、显示 iframe,并清除定时器
- 超时(如 10s)后要主动
layer.close并提示“加载超时”,否则用户会以为卡死
这个逻辑略重,如果只是内网系统且 iframe 页面可控,更推荐改用 type: 1 + AJAX 加载,省去 iframe 的兼容包袱。


















