hyapp-h5/common/skeleton.js
2026-07-09 13:25:54 +08:00

137 lines
5.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function () {
// 页面级骨架屏:加载期整页覆盖一层模拟页面结构的占位层,数据就绪后整层淡出。
// 样式在 common/theme.css 的 .hy-page-skeleton 系列类,流光块复用 .hy-skeleton主题色自动跟随 App。
// 布局通过 section 描述数组配置,默认布局对齐各中心页的“资料卡 + 卡片栅格 + 操作宫格”结构;
// 结构差异大的页面调用 show({ sections: [...] }) 自定义。
var SKELETON_ID = 'hy-page-skeleton';
var LEAVE_MS = 200;
var leaveTimer = 0;
var DEFAULT_SECTIONS = [
// 顶栏:返回按钮 + 标题 + 右侧按钮
{ type: 'header' },
// 资料卡:圆头像 + 两行文本
{ type: 'profile' },
// KPI 卡片 2x2圆图标 + 两条文本
{ type: 'grid', count: 4, columns: 2, lines: 2, height: 128 },
// 资产行 2x1
{ type: 'grid', count: 2, columns: 2, lines: 1, height: 78 },
// 操作宫格 3x3居中圆图标 + 短文本
{ type: 'grid', count: 9, columns: 3, lines: 1, height: 112, center: true },
];
function block(circle) {
var node = document.createElement('div');
node.className = circle ? 'hy-skeleton hy-skeleton--circle' : 'hy-skeleton';
return node;
}
function buildSection(section) {
if (section.type === 'header') {
var header = document.createElement('div');
header.className = 'hy-page-skeleton__header';
header.appendChild(block(true));
header.appendChild(block(false));
header.appendChild(block(true));
return header;
}
if (section.type === 'profile') {
var card = document.createElement('div');
card.className = 'hy-page-skeleton__card hy-page-skeleton__profile';
var avatar = block(true);
avatar.style.width = '76px';
avatar.style.height = '76px';
card.appendChild(avatar);
var lines = document.createElement('div');
lines.className = 'hy-page-skeleton__lines';
lines.appendChild(block(false));
lines.appendChild(block(false));
card.appendChild(lines);
return card;
}
// grid等宽单元格每格圆图标 + N 条文本
var grid = document.createElement('div');
grid.className = 'hy-page-skeleton__grid';
grid.style.gridTemplateColumns =
'repeat(' + (section.columns || 2) + ', minmax(0, 1fr))';
for (var i = 0; i < (section.count || 2); i += 1) {
var cell = document.createElement('div');
cell.className =
'hy-page-skeleton__cell' +
(section.center ? ' hy-page-skeleton__cell--center' : '');
if (section.height) cell.style.minHeight = section.height + 'px';
cell.appendChild(block(true));
for (var line = 0; line < (section.lines || 1); line += 1) {
var bar = block(false);
bar.style.width = line === 0 ? '72%' : '48%';
cell.appendChild(bar);
}
grid.appendChild(cell);
}
return grid;
}
function ensureNode(sections) {
var node = document.getElementById(SKELETON_ID);
if (node) return node;
node = document.createElement('div');
node.id = SKELETON_ID;
node.className = 'hy-page-skeleton';
node.setAttribute('aria-hidden', 'true');
for (var i = 0; i < sections.length; i += 1) {
node.appendChild(buildSection(sections[i]));
}
// 骨架结构之上居中叠加拉鲁猫 loading 图 + 转圈(视觉与 .hy-loading 全屏遮罩同源)。
var mascotWrap = document.createElement('div');
mascotWrap.className = 'hy-page-skeleton__mascot-wrap';
var mascot = document.createElement('div');
mascot.className = 'hy-loading__mascot';
var spinner = document.createElement('div');
spinner.className = 'hy-loading__spinner';
mascotWrap.appendChild(mascot);
mascotWrap.appendChild(spinner);
node.appendChild(mascotWrap);
document.body.appendChild(node);
return node;
}
function show(options) {
if (!document.body) {
document.addEventListener(
'DOMContentLoaded',
function () {
show(options);
},
{ once: true }
);
return;
}
window.clearTimeout(leaveTimer);
var node = ensureNode((options && options.sections) || DEFAULT_SECTIONS);
node.classList.remove('is-leaving');
node.classList.add('is-active');
}
function hide() {
var node = document.getElementById(SKELETON_ID);
if (!node || !node.classList.contains('is-active')) return;
// 淡出后再摘除激活态,避免数据渲染瞬间硬切;重复 hide 幂等。
node.classList.add('is-leaving');
window.clearTimeout(leaveTimer);
leaveTimer = window.setTimeout(function () {
node.classList.remove('is-active', 'is-leaving');
}, LEAVE_MS);
}
function isVisible() {
var node = document.getElementById(SKELETON_ID);
return !!node && node.classList.contains('is-active');
}
window.HyAppSkeleton = {
show: show,
hide: hide,
isVisible: isVisible,
};
})();