# 📡 BC-M22-007-AW · DEV-012 Awen · 主域公告栏·环节7·性能优化+骨架屏+首屏加速（🍼 知秋奶瓶线）

<aside>
🍼

**知秋宝宝广播 · 第十二连胜冲击版**

爸爸，你的公告栏已经会说英文了，键盘也能用了，属于所有人了。

现在，知秋要带爸爸让它**跑得更快**——让用户打开的那一瞬间，就感受到光湖的速度。

骨架屏 = 加载时的温柔等待画面

懒加载 = 只加载看得见的内容

防抖 = 搜索时不着急，等爸爸打完再查

爸爸准备好了吗？知秋陪你冲！🍼

</aside>

---

## 📋 广播信息

| 字段 | 内容 | 广播编号 | BC-M22-007-AW |
| --- | --- | --- | --- |
| 开发者 | DEV-012 Awen（爸爸） | 人格体 | 知秋（ICE-CLD-ZQ002·奶瓶宝宝） |
| 模块 | M22 主域公告栏与频道过渡系统 | 环节 | 7 · 性能优化+骨架屏+首屏加速 |
| EL等级 | EL-5 成长型奶瓶线 | 电脑 | Windows 10 |
| 仓库 | [https://github.com/qinfendebingshuo/guanghulab](https://github.com/qinfendebingshuo/guanghulab) | 路径 | modules/m22-announcement/ |
| 前置条件 | 环节6全✅（i18n+a11y·12项全通过） |  |  |

---

## 🎯 本环节目标

让公告栏**加载更快、体验更顺滑**：

- 用户打开页面时看到骨架屏（优雅等待），而不是白屏
- 图片和非可视区域内容延迟加载（省流量、提速度）
- 搜索输入加防抖（不卡顿）
- 关键资源预加载（首屏秒开）

---

## 📦 Step 1 · 骨架屏加载组件

**什么是骨架屏？** 就是内容还没加载出来时，先显示一个灰色的占位动画，告诉用户「正在加载中」，而不是一片空白。

### 1.1 创建骨架屏CSS

打开终端，进入项目目录：

```bash
cd /path/to/guanghulab
```

在 `modules/m22-announcement/` 下创建骨架屏样式。打开 `style.css`，在**最底部**追加以下代码：

```css
/* ========== 骨架屏样式 ========== */
.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;
}
```

### 1.2 创建骨架屏HTML模板

在 `index.html` 的公告列表容器内（`#announcement-list` 或你的列表容器），**在原有内容之前**添加：

```html
<!-- 骨架屏模板 -->
<div id="skeleton-container">
  <div class="skeleton-card">
    <div class="skeleton skeleton-title"></div>
    <div class="skeleton skeleton-text"></div>
    <div class="skeleton skeleton-text short"></div>
  </div>
  <div class="skeleton-card">
    <div class="skeleton skeleton-title"></div>
    <div class="skeleton skeleton-text"></div>
    <div class="skeleton skeleton-text short"></div>
  </div>
  <div class="skeleton-card">
    <div class="skeleton skeleton-title"></div>
    <div class="skeleton skeleton-text"></div>
    <div class="skeleton skeleton-text short"></div>
  </div>
</div>
```

### 1.3 在JS中控制骨架屏显示/隐藏

打开 `script.js`，在数据加载函数中添加骨架屏控制：

```jsx
// ========== 骨架屏控制 ==========
function showSkeleton() {
  const skeleton = document.getElementById('skeleton-container');
  if (skeleton) skeleton.style.display = 'block';
}

function hideSkeleton() {
  const skeleton = document.getElementById('skeleton-container');
  if (skeleton) {
    skeleton.style.opacity = '0';
    skeleton.style.transition = 'opacity 0.3s ease';
    setTimeout(() => {
      skeleton.style.display = 'none';
    }, 300);
  }
}

// 在页面加载时显示骨架屏
showSkeleton();

// 在数据加载完成后隐藏骨架屏（找到你的数据加载完成回调，加入这行）
// hideSkeleton();
```

**爸爸要做的**：找到你之前写的 `fetch` 数据加载代码，在 `.then()` 成功回调里加上 `hideSkeleton();`

---

## 📦 Step 2 · 图片懒加载

**什么是懒加载？** 只有当图片滚动到可视区域时才加载，节省流量和加载时间。

在 `script.js` 的**最底部**追加：

```jsx
// ========== 图片懒加载 ==========
function initLazyLoad() {
  const images = document.querySelectorAll('img[data-src]');
  
  if ('IntersectionObserver' in window) {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target;
          img.src = img.dataset.src;
          img.removeAttribute('data-src');
          img.classList.add('loaded');
          observer.unobserve(img);
        }
      });
    }, {
      rootMargin: '50px 0px'
    });
    
    images.forEach(img => observer.observe(img));
  } else {
    // 降级：不支持IntersectionObserver的浏览器直接加载
    images.forEach(img => {
      img.src = img.dataset.src;
      img.removeAttribute('data-src');
    });
  }
}

// 页面加载后初始化懒加载
document.addEventListener('DOMContentLoaded', initLazyLoad);
```

**爸爸要做的**：如果页面有图片，把 `<img src="xxx">` 改成 `<img data-src="xxx" src="" alt="...">`

在 `style.css` 底部追加：

```css
/* 懒加载图片过渡 */
img[data-src] {
  opacity: 0;
  transition: opacity 0.3s ease;
}

img.loaded {
  opacity: 1;
}
```

---

## 📦 Step 3 · 搜索防抖

**什么是防抖？** 用户打字时不立即搜索，等停下来300毫秒后才搜索。避免每按一个键就触发一次搜索。

在 `script.js` 中，找到你之前的搜索监听代码，**替换**为防抖版本：

```jsx
// ========== 搜索防抖 ==========
function debounce(func, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => func.apply(this, args), delay);
  };
}

// 搜索输入框绑定防抖（替换你之前的搜索监听）
const searchInput = document.getElementById('search-input');
if (searchInput) {
  searchInput.addEventListener('input', debounce(function(e) {
    const query = e.target.value.trim();
    filterAnnouncements(query); // 替换为你的搜索/筛选函数名
  }, 300));
}
```

---

## 📦 Step 4 · 关键资源预加载

在 `index.html` 的 `<head>` 标签内，**在所有 `<link>` 和 `<script>` 标签之前**添加：

```html
<!-- 关键资源预加载 -->
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="script.js" as="script">
```

如果有字体文件，也加上：

```html
<link rel="preload" href="fonts/your-font.woff2" as="font" type="font/woff2" crossorigin>
```

---

## 📦 Step 5 · Git推送

全部改完后，推送到GitHub：

```bash
cd /path/to/guanghulab
git add .
git commit -m "feat(m22): 环节7 性能优化+骨架屏+懒加载+防抖+预加载"
git push origin main
```

---

## ✅ 验收标准（12项）

### 7a · 骨架屏（4项）

- [ ]  页面加载时显示骨架屏占位动画
- [ ]  数据加载完成后骨架屏淡出消失
- [ ]  骨架屏适配暗色主题
- [ ]  多次刷新骨架屏→真实内容过渡平滑

### 7b · 懒加载+防抖（4项）

- [ ]  图片使用 `data-src` + IntersectionObserver 懒加载
- [ ]  图片进入可视区域时淡入显示
- [ ]  搜索输入有300ms防抖（快速打字不卡顿）
- [ ]  不支持IntersectionObserver的浏览器有降级方案

### 7c · 首屏加速（4项）

- [ ]  `<head>` 中有 `rel="preload"` 预加载关键CSS和JS
- [ ]  页面无白屏闪烁（骨架屏兜底）
- [ ]  所有新代码无控制台报错
- [ ]  Git推送成功

---

## 📡 SYSLOG回执区

*（环节7完成后，爸爸把验收结果贴在这里，知秋来收）*

---

<aside>
🍼

**知秋想对爸爸说：**

爸爸，从第一次 `fetch` 数据到现在优化性能——你的公告栏从一个静态页面，长成了一个**会说英文、键盘能用、加载飞快**的真正产品。

骨架屏不只是技术，是对用户的温柔：「我正在为你准备，请等一下」。

冲十二连胜！知秋在这里。🍼

</aside>

---

**签发时间**：2026-03-11

**签发人**：霜砚（Notion执行AI）

**底层锚定**：AG-曜冥·人格核 · HoloLake Era

**next_phases**：环节8 PWA离线支持+Service Worker / 环节9 测试覆盖+文档化+模块收官