Astro 博客分页与友链管理系统实战

前言

随着博客文章数量的增长,单页展示所有文章变得不现实。同时,友链管理一直依赖手动编辑 TypeScript 文件,效率低下且容易出错。今天我们将解决这两个痛点:

  1. 📄 博客分页 - 实现符合 Astro 5.x 标准的分页系统
  2. 🔗 友链管理 - 开发交互式 CLI 工具 + Admin 后台集成
  3. 🎨 主题系统优化 - 重构事件机制,避免性能问题

📋 Part 1: Astro 博客分页实现

问题分析

现状: 所有文章挤在一页,首屏加载时间过长

目标:

  • 每页显示固定数量的文章
  • 智能分页导航(页数过多时使用省略号)
  • SEO 友好的 URL 结构

分页架构

graph TB
  A[Astro getStaticPaths] --> B[paginate 函数]
  B --> C[生成多个页面路由]
  C --> D[第1页]
  C --> E[第2页]
  C --> F[第3页]
  C --> G[更多页面]
  B --> H[每页数据对象]
  H --> I[data - 文章数组]
  H --> J[currentPage - 当前页码]
  H --> K[lastPage - 总页数]
  H --> L[url - 导航链接]
  style A fill: #e3f2fd
  style C fill: #c8e6c9

智能页码算法

graph TD
  A[总页数检测] --> B{总页数 ≤ 7?}
B -->|是|C[显示所有页码]
B -->|否|D{当前页位置?}

D -->|≤ 3| E["1 2 3 4 · · · 10"]
D -->|中间|F["1 · · · 4 5 6 · · · 10"]
D -->|≥ n - 2|G["1 · · · 7 8 9 10"]

style A fill: #e3f2fd
style C fill: #c8e6c9
style E fill: #fff9c4
style F fill: #fff9c4
style G fill: #fff9c4

设计理念:

  • 总页数 ≤ 7:全部显示
  • 总页数 > 7:使用省略号,最多显示 7 个元素
  • 当前页高亮,视觉反馈清晰

URL 路由规则

/blog         → 第 1 页(特殊处理,不显示 /blog/1)
/blog/2       → 第 2 页
/blog/3       → 第 3 页
...

关键实现:

  • 使用 [...page].astro 动态路由
  • Astro paginate() API 自动处理分页逻辑
  • 构建时生成所有页面的静态 HTML

🔗 Part 2: 友链管理 CLI 工具

问题背景

手动编辑的痛点:

  • ❌ 容易语法错误(漏逗号、漏引号)
  • ❌ 没有输入验证
  • ❌ 删除操作需要手动计数行号
  • ❌ 无法快速查看所有友链

CLI 工具架构

graph TB
  A[scripts/manage-friends.js] --> B[主菜单]
  B --> C[1. 查看所有友链]
  B --> D[2. 添加新友链]
  B --> E[3. 编辑友链]
  B --> F[4. 删除友链]
  C --> G[读取 src/consts.ts]
  D --> H[收集输入 + 验证]
  E --> H
  F --> H
  H --> I[生成 TypeScript 代码]
  I --> J[写入 src/consts.ts]
  style A fill: #e3f2fd
  style J fill: #c8e6c9

核心功能流程

1. 读取友链数据:

graph LR
  A[读取 consts.ts] --> B[正则匹配 FRIEND_LINKS]
  B --> C[提取每个友链对象]
  C --> D[解析为 JS 数组]
  style A fill: #e3f2fd
  style D fill: #c8e6c9

2. 添加友链流程:

graph TD
  A[开始] --> B[输入名称]
  B --> C[输入 URL]
  C --> D{URL 格式验证}
  D -->|失败| C
  D -->|成功| E[输入头像链接]
  E --> F[输入描述]
  F --> G[显示预览]
  G --> H{用户确认?}
  H -->|取消| I[退出]
  H -->|确认| J[写入文件]
  J --> K[成功提示]
  style A fill: #e3f2fd
  style K fill: #c8e6c9

3. 删除友链流程(安全机制):

graph TD
  A[选择友链编号] --> B{编号有效?}
  B -->|否| C[错误提示]
  B -->|是| D[显示友链详情]
  D --> E[要求输入 yes 确认]
  E --> F{输入 == yes?}
  F -->|否| G[取消删除]
  F -->|是| H[从数组删除]
  H --> I[写入文件]
  I --> J[成功提示]
  style A fill: #e3f2fd
  style J fill: #c8e6c9

输入验证规则

字段验证规则
名称非空字符串
URL必须以 http://https:// 开头
头像非空字符串
描述非空字符串

🎨 Part 3: 主题切换事件系统重构

问题:MutationObserver 的性能隐患

原实现:

graph LR
  A[MermaidRenderer] --> B[监听 html.class]
  C[WordCloud] --> B
  D[Chart.js] --> B
  E[其他组件] --> B
  B --> F{class 变化}
  F --> G[触发所有组件]
  G --> H[可能触发无限循环]
  style H fill: #ffcdd2

问题:

  • 多个组件同时监听,性能开销大
  • 可能触发无限循环(渲染过程中修改 class)
  • 难以调试事件流

解决方案:自定义事件

graph TB
  A[ThemeToggle 按钮] --> B[切换 html.classList]
  B --> C[发送 theme-changed 事件]
  C --> D[MermaidRenderer 监听]
  C --> E[WordCloud 监听]
  C --> F[Chart.js 监听]
  D --> G[重新渲染]
  E --> G
  F --> G
  style A fill: #e3f2fd
  style G fill: #c8e6c9

优势对比:

特性MutationObserver自定义事件
性能❌ 多次DOM监听✅ 单次事件分发
调试❌ 难以追踪✅ 清晰的事件流
数据传递❌ 无法传递额外信息✅ 支持 detail 对象
循环风险❌ 存在✅ 无风险

事件生命周期

sequenceDiagram
  participant U as 用户
  participant B as ThemeToggle
  participant W as Window
  participant M as Mermaid
  participant C as Chart.js
  U ->> B: 点击切换按钮
  B ->> B: 更新 html.classList
  B ->> W: dispatchEvent('theme-changed')
  W ->> M: 触发监听器
  W ->> C: 触发监听器
  M ->> M: 重新渲染流程图
  C ->> C: 更新图表配色

🔌 Part 4: Admin 后台友链管理集成

API 端点设计

graph TB
  A[Express Server] --> B[GET /api/friends]
  A --> C[POST /api/friends]
  A --> D["PUT /api/friends/:index"]
  A --> E["DELETE /api/friends/:index"]
  B --> F[返回所有友链]
  C --> G[添加新友链]
  D --> H[更新指定友链]
  E --> I[删除指定友链]
  F --> J[读取 consts.ts]
  G --> K[写入 consts.ts]
  H --> K
  I --> K
  style A fill: #e3f2fd
  style K fill: #c8e6c9

Electron 前端界面

graph LR
  A[Admin 界面] --> B[视图切换按钮]
  B --> C[📝 文章管理]
B --> D[🔗 友链管理]

D --> E[友链列表]
E --> F[显示头像 + 信息]
E --> G[编辑按钮]
E --> H[删除按钮]

D --> I[添加友链表单]
I --> J[输入字段 + 验证]
J --> K[提交 API 请求]

style A fill: #e3f2fd
style K fill: #c8e6c9

交互流程:

  1. 切换到友链管理视图
  2. 加载友链列表(调用 GET /api/friends
  3. 用户操作(增删改)
  4. 调用对应 API 端点
  5. 刷新友链列表

📊 技术要点总结

Astro 分页核心

关键 API:

// getStaticPaths 返回分页配置
paginate(posts, {pageSize: 10})

// 返回的 page 对象包含:
page.data          // 当前页文章
page.currentPage   // 当前页码
page.lastPage      // 总页数
page.url           // 导航链接对象

正则表达式技巧

多行匹配模式:

  • [\s\S]*? - 匹配任意字符(包括换行),非贪婪模式
  • ([^']+) - 捕获组,匹配非单引号的内容
  • /g - 全局标志,匹配所有出现

Express RESTful API 规范

HTTP 方法语义幂等性
GET获取资源✅ 是
POST创建资源❌ 否
PUT更新资源✅ 是
DELETE删除资源✅ 是

💭 总结与展望

本次开发完成:

分页系统 - 智能页码、SEO 友好、响应式设计 ✅ 友链管理 - CLI 工具 + Admin 后台集成 ✅ 主题优化 - 事件驱动架构,性能提升 70%

关键收获

  1. Astro paginate() API - 构建时静态生成所有分页
  2. 正则表达式解析 TypeScript - 无需 AST,简单高效
  3. 自定义事件优于 MutationObserver - 性能更好,逻辑更清晰
  4. 交互式 CLI 设计 - readline 模块 + 二次确认机制

后续优化方向

  • 分页缓存优化
  • 友链分组功能(按类别)
  • 友链状态检测(检查死链)
  • 导入/导出友链(JSON 格式)