diff --git a/modules/M22-bulletin/index.html b/modules/M22-bulletin/index.html index 82e85611..e81addec 100644 --- a/modules/M22-bulletin/index.html +++ b/modules/M22-bulletin/index.html @@ -4,6 +4,10 @@ HoloLake公告栏 + + + + @@ -22,13 +26,32 @@ - + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -40,7 +63,7 @@ - + diff --git a/modules/M22-bulletin/script.js b/modules/M22-bulletin/script.js index 9c1950b9..0473d39e 100644 --- a/modules/M22-bulletin/script.js +++ b/modules/M22-bulletin/script.js @@ -1,5 +1,5 @@ // ===== script.js ===== -// 知秋:主逻辑·动态渲染+loading+错误处理+i18n+无障碍 +// 知秋:主逻辑·动态渲染+错误处理+i18n+无障碍+骨架屏 (function() { // 状态变量 @@ -11,21 +11,39 @@ // DOM元素 const container = document.querySelector('.bulletin-container'); const channelTabs = document.querySelectorAll('.channel-tab'); + const skeletonContainer = document.getElementById('skeleton-container'); + + // ========== 骨架屏控制 ========== + function showSkeleton() { + if (skeletonContainer) { + skeletonContainer.style.display = 'block'; + } + } + + function hideSkeleton() { + if (skeletonContainer) { + skeletonContainer.style.opacity = '0'; + skeletonContainer.style.transition = 'opacity 0.3s ease'; + setTimeout(() => { + skeletonContainer.style.display = 'none'; + }, 300); + } + } // 初始化 async function init() { - console.log("【知秋】M22公告栏·环节6启动"); + console.log("【知秋】M22公告栏·环节7启动"); // 监听语言切换事件 window.addEventListener('languagechange', () => { - render(); // 语言变了,重新渲染 + render(); }); - await loadBulletins(); // 加载数据 - render(); // 初次渲染 - setupEventListeners(); // 频道切换事件 - setupLangSwitcher(); // 语言切换器事件 - setupKeyboardNavigation(); // 键盘导航 + await loadBulletins(); + render(); + setupEventListeners(); + setupLangSwitcher(); + setupKeyboardNavigation(); } // 语言切换器 @@ -34,12 +52,10 @@ btn.addEventListener('click', () => { const lang = btn.dataset.lang; window.i18n.switchLang(lang); - // 更新按钮激活状态 document.querySelectorAll('.lang-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); }); }); - // 设置当前语言按钮激活状态 const currentLang = window.i18n.currentLang; document.querySelectorAll('.lang-btn').forEach(btn => { if (btn.dataset.lang === currentLang) { @@ -48,9 +64,8 @@ }); } - // 键盘导航 + // 键盘导航 function setupKeyboardNavigation() { - // 给每个频道标签加上键盘事件 const tabs = document.querySelectorAll('.channel-tab'); tabs.forEach(tab => { @@ -61,13 +76,11 @@ e.preventDefault(); const nextIndex = (currentIndex + 1) % tabs.length; tabs[nextIndex].focus(); - // 自动激活聚焦的标签 tabs[nextIndex].click(); } else if (e.key === 'ArrowLeft') { e.preventDefault(); const prevIndex = (currentIndex - 1 + tabs.length) % tabs.length; tabs[prevIndex].focus(); - // 自动激活聚焦的标签 tabs[prevIndex].click(); } else if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); @@ -75,47 +88,26 @@ } }); }); - - // 也可以保留原来的 channel-bar 监听作为备用 - const channelBar = document.querySelector('.channel-bar'); - if (channelBar) { - channelBar.addEventListener('keydown', (e) => { - // 防止重复处理 - if (e.target.classList.contains('channel-tab')) return; - - const tabs = Array.from(document.querySelectorAll('.channel-tab')); - const currentIndex = tabs.findIndex(tab => tab === document.activeElement); - - if (e.key === 'ArrowRight') { - e.preventDefault(); - const nextIndex = (currentIndex + 1) % tabs.length; - tabs[nextIndex].focus(); - tabs[nextIndex].click(); - } else if (e.key === 'ArrowLeft') { - e.preventDefault(); - const prevIndex = (currentIndex - 1 + tabs.length) % tabs.length; - tabs[prevIndex].focus(); - tabs[prevIndex].click(); - } - }); - } } - // 加载公告(核心!) + + // 加载公告 async function loadBulletins() { + showSkeleton(); // 显示骨架屏 loading = true; error = null; - render(); // 显示loading try { const data = await API.fetchBulletins(); allBulletins = data; + hideSkeleton(); // 数据到手,隐藏骨架屏 loading = false; - render(); + render(); // 渲染真实内容 } catch (err) { console.error("加载失败:", err); + hideSkeleton(); // 出错也要隐藏骨架屏 loading = false; error = "error"; - render(); + render(); // 显示错误状态 } } @@ -123,17 +115,6 @@ function render() { if (!container) return; - // 加载状态 - if (loading) { - container.innerHTML = ` -
-
-

${window.i18n.t('loading')}

-
- `; - return; - } - // 错误状态 if (error) { const isOffline = !navigator.onLine; @@ -178,13 +159,12 @@ return; } - // 使用环节4的createCard(如果不存在就降级) + // 渲染公告卡片 let html = ''; filtered.forEach((item, index) => { if (typeof createCard === 'function') { html += createCard(item); } else { - // 降级方案(保证显示) html += `

${item.title}

@@ -200,7 +180,7 @@ container.innerHTML = html; } - // 事件监听(频道切换) + // 频道切换事件 function setupEventListeners() { channelTabs.forEach(tab => { tab.addEventListener('click', (e) => { diff --git a/modules/M22-bulletin/style.css b/modules/M22-bulletin/style.css index 351c2abb..3ffffa9f 100644 --- a/modules/M22-bulletin/style.css +++ b/modules/M22-bulletin/style.css @@ -520,4 +520,46 @@ body { background: black; border-color: black; } +} +/* ========== 骨架屏样式 ========== */ +.skeleton { + background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); + background-size: 200% 100%; + animation: skeleton-loading 1.5s infinite; + border-radius: 4px; +} + +@keyframes skeleton-loading { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +.skeleton-text { + height: 16px; + margin-bottom: 8px; + width: 80%; +} + +.skeleton-text.short { + width: 40%; +} + +.skeleton-title { + height: 24px; + margin-bottom: 12px; + width: 60%; +} + +.skeleton-card { + padding: 16px; + border-radius: 8px; + background: var(--card-bg, #fff); + margin-bottom: 12px; +} + +/* 暗色主题适配 */ +[data-theme="dark"] .skeleton { + background: linear-gradient(90deg, #2a2a2a 25%, #333 50%, #2a2a2a 75%); + background-size: 200% 100%; + animation: skeleton-loading 1.5s infinite; } \ No newline at end of file