(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, }; })();