(function () { // 通用全屏 loading(拉鲁猫吉祥物 + 转圈)。 // 样式复用 common/theme.css 的 .hy-loading 系列类:新页面按仓库约定必须引入 theme.css, // 组件自身只负责 DOM 注入和显隐状态,不重复维护一份样式副本避免两处漂移。 // 吉祥物图取 theme.css 默认值(lalu 紫猫动画 webp);其他 app 主题可在 // [data-hy-app-code='...'] 下覆盖 .hy-loading__mascot 的 background 换皮。 var LOADING_ID = 'hy-global-loading'; // show/hide 采用引用计数:并发请求各自 show/hide 时,最后一个 hide 才真正关闭遮罩, // 避免先完成的请求把还在加载的请求的遮罩提前关掉。 var visibleCount = 0; function ensureNode() { var node = document.getElementById(LOADING_ID); if (node) return node; node = document.createElement('div'); node.id = LOADING_ID; node.className = 'hy-loading'; node.setAttribute('role', 'status'); node.setAttribute('aria-live', 'polite'); node.setAttribute('aria-hidden', 'true'); var mascot = document.createElement('div'); mascot.className = 'hy-loading__mascot'; mascot.setAttribute('aria-hidden', 'true'); var spinner = document.createElement('div'); spinner.className = 'hy-loading__spinner'; spinner.setAttribute('aria-hidden', 'true'); var text = document.createElement('div'); text.className = 'hy-loading__text'; text.hidden = true; node.appendChild(mascot); node.appendChild(spinner); node.appendChild(text); document.body.appendChild(node); return node; } function render() { var node = ensureNode(); var active = visibleCount > 0; node.classList.toggle('is-active', active); node.setAttribute('aria-hidden', active ? 'false' : 'true'); } function setText(node, message) { var text = node.querySelector('.hy-loading__text'); if (!text) return; var value = String(message || '').trim(); // 文案由调用方传入已本地化的字符串;组件不内置多语言字典(common/i18n.js 归页面消费)。 text.textContent = value; text.hidden = !value; } function show(options) { if (!document.body) { // 页面脚本可能在 body 就绪前调用;挂到 DOMContentLoaded 重放,保持调用方无需关心时序。 document.addEventListener( 'DOMContentLoaded', function () { show(options); }, { once: true } ); return; } visibleCount += 1; var node = ensureNode(); setText(node, options && options.text); render(); } function hide(force) { if (force) { visibleCount = 0; } else if (visibleCount > 0) { visibleCount -= 1; } if (!document.getElementById(LOADING_ID)) return; render(); } function isVisible() { return visibleCount > 0; } window.HyAppLoading = { show: show, hide: hide, isVisible: isVisible, }; // 与 HyAppToast 的 hyapp:toast 对齐的事件桥:原生壳或其他脚本可通过事件控制遮罩。 window.addEventListener('hyapp:loading', function (event) { var detail = event.detail || {}; if (detail.visible === false) { hide(detail.force === true); return; } show(detail); }); })();