|
1 | 1 | # 核心逻辑实现 |
2 | 2 |
|
3 | | -## 功能模块说明 |
| 3 | +## 项目概述 |
| 4 | + |
| 5 | +MARKDOWN.HTML 是一个低依赖、一键部署的 Markdown 网页渲染解决方案。项目通过单一 HTML 文件实现完整的 Markdown 渲染功能,支持代码高亮、Mermaid 图表、多语言翻译、深色模式等特性。 |
| 6 | + |
| 7 | +## 核心架构 |
| 8 | + |
| 9 | +项目采用客户端渲染架构,主要包含以下核心模块: |
4 | 10 |
|
5 | 11 | ```mermaid |
6 | | -classDiagram |
7 | | - class ContentLoader { |
8 | | - +showMarkdown(mdPath, response) |
9 | | - +getMarkdown() |
10 | | - +handleError() |
11 | | - +updateContent() |
12 | | - } |
13 | | - class NavigationHandler { |
14 | | - +initPJAX() |
15 | | - +initCustomPJAXResponse() |
16 | | - +initCustomPJAXEventListener() |
17 | | - +customPushState() |
18 | | - } |
19 | | - class TranslationSystem { |
20 | | - +initTranslate() |
21 | | - +refreshTranslate() |
22 | | - +infoTranslate() |
23 | | - } |
24 | | - class UIStateManager { |
25 | | - +loadingState 计数器 |
26 | | - +startLoad() |
27 | | - +endLoad() |
28 | | - +initDarkmode() |
29 | | - } |
30 | | - class PathProcessor { |
31 | | - +decodeMDPath() |
32 | | - +formatMDPath() |
33 | | - +getDirectory() |
34 | | - +isRelativePath() |
35 | | - } |
36 | | - |
37 | | - ContentLoader --> NavigationHandler : 使用PJAX导航 |
38 | | - ContentLoader --> PathProcessor : 路径处理 |
39 | | - ContentLoader --> TranslationSystem : 内容翻译 |
40 | | - NavigationHandler --> ContentLoader : 触发加载 |
41 | | - UIStateManager --> ContentLoader : 加载状态控制 |
| 12 | +graph TB |
| 13 | + A[HTML 入口文件] --> B[Markdown 渲染引擎] |
| 14 | + A --> C[资源内联系统] |
| 15 | + A --> D[构建处理系统] |
| 16 | + B --> E[marked.js] |
| 17 | + B --> F[highlight.js] |
| 18 | + B --> G[mermaid.js] |
| 19 | + C --> H[Rust 构建工具] |
| 20 | + D --> I[GitHub Actions] |
42 | 21 | ``` |
43 | 22 |
|
44 | | -## 核心流程 |
| 23 | +## 1. HTML 渲染逻辑 |
45 | 24 |
|
46 | | -```mermaid |
47 | | -sequenceDiagram |
48 | | - participant 用户 |
49 | | - participant 浏览器 |
50 | | - participant ContentLoader |
51 | | - participant NavigationHandler |
52 | | - |
53 | | - 用户->>浏览器: 访问页面 |
54 | | - 浏览器->>ContentLoader: DOMContentLoaded |
55 | | - ContentLoader->>PathProcessor: decodeMDPath(URL) |
56 | | - alt 路径有效 |
57 | | - ContentLoader->>ContentLoader: fetchMD(路径) |
58 | | - ContentLoader->>ContentLoader: 解析 Markdown |
59 | | - ContentLoader->>ContentLoader: 处理内部链接转换 |
60 | | - ContentLoader->>UIStateManager: startLoad() |
61 | | - ContentLoader->>DOM: updateContent() |
62 | | - ContentLoader->>TranslationSystem: 触发翻译 |
63 | | - ContentLoader->>UIStateManager: endLoad() |
64 | | - else 路径无效 |
65 | | - ContentLoader->>PathProcessor: 尝试默认文件(index.md/README.md) |
66 | | - ContentLoader->>UIStateManager: handleError() |
67 | | - end |
68 | | - |
69 | | - 用户->>NavigationHandler: 点击 .md 链接 |
70 | | - NavigationHandler->>ContentLoader: 触发新内容加载 |
| 25 | +### 1.1 版本管理机制 |
| 26 | + |
| 27 | +版本号存储在 `index.html` 的自定义标签中: |
| 28 | + |
| 29 | +```html |
| 30 | +<markdown-html |
| 31 | + version="1.20.2" |
| 32 | + author="PJ568" |
| 33 | + repo="https://github.com/PJ-568/markdown.html" |
| 34 | + license="CC BY-SA 4.0 International" |
| 35 | +></markdown-html> |
71 | 36 | ``` |
72 | 37 |
|
73 | | -## 关键逻辑说明 |
| 38 | +**版本提取逻辑**: |
| 39 | + |
| 40 | +- 通过 `getVersion()` 函数从 DOM 中提取版本信息 |
| 41 | +- 用于显示关于信息和版本检测 |
| 42 | + |
| 43 | +### 1.2 Markdown 渲染流程 |
| 44 | + |
| 45 | +#### 主要渲染函数:`showMarkdown()` |
| 46 | + |
| 47 | +**核心流程**: |
| 48 | + |
| 49 | +1. **路径解析**:通过 `decodeMDPath()` 解析 URL 参数 `?p=` 指定的 Markdown 文件路径 |
| 50 | +2. **文件检测**:自动检测 `index.md` 或 `README.md` 文件 |
| 51 | +3. **内容获取**:使用 `fetch()` API 获取 Markdown 文件内容 |
| 52 | +4. **渲染处理**:调用 `getMarkdown()` 进行完整渲染 |
| 53 | + |
| 54 | +#### Markdown 处理函数:`getMarkdown()` |
| 55 | + |
| 56 | +**处理步骤**: |
| 57 | + |
| 58 | +1. **原始渲染**:使用 `marked.parse()` 将 Markdown 转换为 HTML |
| 59 | +2. **链接处理**:自动转换相对路径为绝对路径 |
| 60 | +3. **图片处理**:设置懒加载属性,转换相对路径 |
| 61 | +4. **目录生成**:通过 `generateOutline()` 自动生成文档目录 |
| 62 | +5. **内容包装**:添加文件路径信息和目录结构 |
| 63 | + |
| 64 | +### 1.3 动画与状态管理 |
| 65 | + |
| 66 | +**加载动画系统**: |
| 67 | + |
| 68 | +- `loadingState` 对象管理加载状态 |
| 69 | +- 进度条动画通过 CSS 动画和 JavaScript 定时器实现 |
| 70 | +- 支持多资源加载的并发计数 |
| 71 | + |
| 72 | +**页面切换动画**: |
| 73 | + |
| 74 | +- 使用 CSS 动画实现页面切换效果 |
| 75 | +- `waitForAnimationsEnd()` 函数等待动画完成 |
| 76 | + |
| 77 | +## 2. 多语言支持系统 |
| 78 | + |
| 79 | +### 2.1 翻译引擎集成 |
| 80 | + |
| 81 | +**初始化流程**:`initTranslate()` |
| 82 | + |
| 83 | +1. 配置 translate.js 使用客户端翻译服务 |
| 84 | +2. 设置自动语言检测 |
| 85 | +3. 配置忽略翻译的 CSS 类 |
| 86 | +4. 执行初始翻译 |
| 87 | + |
| 88 | +**翻译提示系统**:`infoTranslate()` |
| 89 | + |
| 90 | +- 检测当前语言与原始语言的差异 |
| 91 | +- 动态生成翻译提示信息 |
| 92 | +- 提供切换回原始语言的按钮 |
| 93 | + |
| 94 | +### 2.2 语言切换处理 |
| 95 | + |
| 96 | +**自动检测**: |
| 97 | + |
| 98 | +- 通过 URL 参数控制语言切换 |
| 99 | +- 支持浏览器语言偏好设置 |
| 100 | + |
| 101 | +**手动切换**: |
| 102 | + |
| 103 | +- 通过 `translate.changeLanguage()` 函数实现语言切换 |
| 104 | + |
| 105 | +## 3. PJAX 无刷新导航 |
| 106 | + |
| 107 | +### 3.1 PJAX 初始化 |
| 108 | + |
| 109 | +**配置**:`initPJAX()` |
| 110 | + |
| 111 | +- 选择器配置:`head title`, `.markdown-body`, `.pjax-reload` |
| 112 | +- 动画切换配置:侧滑动画效果 |
| 113 | +- 缓存策略:禁用缓存破坏 |
| 114 | + |
| 115 | +### 3.2 自定义 PJAX 处理 |
| 116 | + |
| 117 | +**响应处理重写**:`initCustomPJAXResponse()` |
| 118 | + |
| 119 | +- 覆写 PJAX 的默认响应处理逻辑 |
| 120 | +- 针对 Markdown 页面进行特殊处理 |
| 121 | +- 保持标准 HTML 页面的正常处理 |
| 122 | + |
| 123 | +**事件监听器**:`initCustomPJAXEventListener()` |
| 124 | + |
| 125 | +- 监听 `.md` 链接的点击事件 |
| 126 | +- 实现自定义的无刷新页面切换 |
| 127 | +- 错误处理和回退机制 |
| 128 | + |
| 129 | +## 4. 深色模式支持 |
| 130 | + |
| 131 | +### 4.1 Darkmode.js 集成 |
| 132 | + |
| 133 | +**初始化**:`initDarkmode()` |
| 134 | + |
| 135 | +- 检测 Darkmode.js 库的可用性 |
| 136 | +- 创建深色模式实例 |
| 137 | +- 错误处理和兼容性保障 |
| 138 | + |
| 139 | +### 4.2 切换控制 |
| 140 | + |
| 141 | +**手动切换**: |
| 142 | + |
| 143 | +- 通过 `darkmode.toggle()` 函数切换模式 |
| 144 | +- 支持跟随系统、浅色、深色三种模式 |
| 145 | + |
| 146 | +## 5. 构建与发布系统 |
| 147 | + |
| 148 | +### 5.1 Rust 构建工具 |
| 149 | + |
| 150 | +项目使用 Rust 编写的构建工具 `src/main.rs` 生成不同版本的 HTML 文件。 |
| 151 | + |
| 152 | +#### 核心功能: |
| 153 | + |
| 154 | +1. **HTML 压缩**:`minify_html()` |
| 155 | + |
| 156 | + - 使用 `minify-html` 库进行压缩 |
| 157 | + - 保留关键标签结构 |
| 158 | + - 压缩 CSS 和 JavaScript |
| 159 | + |
| 160 | +2. **资源内联**:`all_in_one()` |
| 161 | + - 自动下载外部 CSS 和 JavaScript 资源 |
| 162 | + - 使用 `scraper` 库解析 HTML DOM |
| 163 | + - 内联替换外部资源为嵌入式内容 |
| 164 | + |
| 165 | +#### 构建流程: |
| 166 | + |
| 167 | +```bash |
| 168 | +cargo run --release -- index.html |
| 169 | +``` |
| 170 | + |
| 171 | +**生成文件**: |
| 172 | + |
| 173 | +- `index.min.html` - 压缩版本 |
| 174 | +- `index.allinone.html` - 资源内联版本 |
| 175 | +- `index.allinone.min.html` - 压缩的资源内联版本 |
| 176 | + |
| 177 | +### 5.2 版本管理脚本 |
| 178 | + |
| 179 | +#### `scripts/get-version.bash` |
| 180 | + |
| 181 | +- 从 HTML 文件中提取版本号 |
| 182 | +- 支持自定义文件路径 |
| 183 | +- 多语言错误提示 |
| 184 | + |
| 185 | +#### `scripts/is-newer-version.bash` |
| 186 | + |
| 187 | +- 比较当前版本与 Git 标签 |
| 188 | +- 使用 `sort -V` 进行版本号比较 |
| 189 | +- 输出新版本号或 "0"(无更新) |
| 190 | + |
| 191 | +#### `scripts/release.bash` |
| 192 | + |
| 193 | +- 交互式版本发布工具 |
| 194 | +- 版本格式验证(X.X.X) |
| 195 | +- 自动创建和推送 Git 标签 |
| 196 | + |
| 197 | +### 5.3 GitHub Actions 工作流 |
| 198 | + |
| 199 | +**自动化发布流程**: |
| 200 | + |
| 201 | +1. **版本检测**:检查是否需要发布新版本 |
| 202 | +2. **标签创建**:自动创建 vX.X.X 格式标签 |
| 203 | +3. **构建处理**:编译 Rust 程序并生成 HTML 文件 |
| 204 | +4. **发布打包**:准备发布物文件结构 |
| 205 | +5. **发布创建**:创建 GitHub Release 并部署到 Pages |
| 206 | + |
| 207 | +## 6. 错误处理机制 |
| 208 | + |
| 209 | +### 6.1 客户端错误处理 |
| 210 | + |
| 211 | +**文件加载错误**:`handleError()` |
| 212 | + |
| 213 | +- 显示友好的错误信息页面 |
| 214 | +- 提供重新加载和返回功能 |
| 215 | +- 自动恢复页面状态 |
| 216 | + |
| 217 | +**网络请求错误**: |
| 218 | + |
| 219 | +- `fetch()` API 的错误处理 |
| 220 | +- 超时和网络异常检测 |
| 221 | +- 友好的用户提示 |
| 222 | + |
| 223 | +### 6.2 构建时错误处理 |
| 224 | + |
| 225 | +**Rust 错误处理**: |
| 226 | + |
| 227 | +- 自定义 `HtmlProcessorError` 类型 |
| 228 | +- `Result<T, Box<dyn Error>>` 统一错误处理 |
| 229 | +- 详细的错误日志输出 |
| 230 | + |
| 231 | +## 7. 性能优化特性 |
| 232 | + |
| 233 | +### 7.1 懒加载优化 |
| 234 | + |
| 235 | +**图片懒加载**: |
| 236 | + |
| 237 | +- 自动设置 `loading="lazy"` 属性 |
| 238 | +- 减少初始页面加载时间 |
| 239 | + |
| 240 | +**资源按需加载**: |
| 241 | + |
| 242 | +- 外部 CSS 动态加载 |
| 243 | +- 避免阻塞页面渲染 |
| 244 | + |
| 245 | +### 7.2 缓存策略 |
| 246 | + |
| 247 | +**PJAX 缓存**: |
| 248 | + |
| 249 | +- 禁用缓存破坏机制 |
| 250 | +- 提高页面切换速度 |
| 251 | + |
| 252 | +**浏览器缓存**: |
| 253 | + |
| 254 | +- 合理的缓存头设置 |
| 255 | +- 减少重复资源下载 |
| 256 | + |
| 257 | +## 8. 安全考虑 |
| 258 | + |
| 259 | +### 8.1 XSS 防护 |
| 260 | + |
| 261 | +**内容安全策略**: |
74 | 262 |
|
75 | | -### 1. 内容加载流程 (`showMarkdown`) |
| 263 | +- 安全的 HTML 解析和处理 |
| 264 | +- 避免脚本注入风险 |
76 | 265 |
|
77 | | -- **路径解析**:通过 `decodeMDPath()` 解析URL参数 |
78 | | -- **文件获取**:优先尝试 `index.md`,失败后回退 `README.md` |
79 | | -- **链接转换**:将文档内 `.md` 相对路径转换为绝对路径 |
80 | | -- **DOM更新**:使用 `updateContent()` 注入生成的HTML |
81 | | -- **加载状态**:通过 `loadingState` 计数器管理进度条动画 |
| 266 | +**外部资源验证**: |
82 | 267 |
|
83 | | -### 2. PJAX导航系统 |
| 268 | +- 只加载可信的 CDN 资源 |
| 269 | +- 资源完整性检查 |
84 | 270 |
|
85 | | -- **初始化**:`initPJAX()` 配置选择器和切换规则 |
86 | | -- **自定义处理**:覆写`handleResponse` 实现 Markdown 渲染 |
87 | | -- **事件委托**:拦截 .md 链接点击事件触发无刷新加载 |
88 | | -- **状态管理**:`customPushState()` 维护浏览历史层级 |
| 271 | +### 8.2 隐私保护 |
89 | 272 |
|
90 | | -### 3. 翻译系统集成 |
| 273 | +**翻译服务**: |
91 | 274 |
|
92 | | -- **自动检测**:`setAutoDiscriminateLocalLanguage()` 设置语言 |
93 | | -- **DOM注入**:`infoTranslate()` 插入语言切换提示条 |
94 | | -- **动态刷新**:`refreshTranslate()` 处理动态内容翻译 |
| 275 | +- 使用客户端翻译避免数据泄露 |
| 276 | +- 可选的翻译功能 |
95 | 277 |
|
96 | | -### 4. 错误处理机制 |
| 278 | +## 技术栈总结 |
97 | 279 |
|
98 | | -- **分级捕获**:try/catch 块覆盖关键操作节点 |
99 | | -- **友好提示**:`handleError()` 生成带操作按钮的错误界面 |
100 | | -- **状态恢复**:错误后自动回退到可用导航状态 |
| 280 | +| 组件 | 技术 | 用途 | |
| 281 | +| ------------ | ----------------------------------- | ---------------------------- | |
| 282 | +| **前端渲染** | marked.js, highlight.js, mermaid.js | Markdown 解析和渲染 | |
| 283 | +| **用户体验** | translate.js, Darkmode.js, Pjax | 多语言、深色模式、无刷新导航 | |
| 284 | +| **构建工具** | Rust, minify-html, scraper | HTML 压缩和资源内联 | |
| 285 | +| **自动化** | GitHub Actions, Bash 脚本 | 版本管理和发布流程 | |
| 286 | +| **部署** | GitHub Pages, CDN | 静态资源分发 | |
101 | 287 |
|
102 | | -### 5. 动画与状态同步 |
| 288 | +## 核心设计原则 |
103 | 289 |
|
104 | | -- **CSS动画**:使用 `Animated` 类实现页面过渡效果 |
105 | | -- **事件委托**:监听 `animationend` 事件清理DOM残留 |
106 | | -- **滚动管理**:内容加载后自动滚动到顶部 |
| 290 | +1. **低依赖**:单一 HTML 文件包含所有必要功能 |
| 291 | +2. **模块化**:各功能组件独立且可替换 |
| 292 | +3. **可扩展**:易于添加新功能和集成 |
| 293 | +4. **性能优先**:优化加载速度和用户体验 |
| 294 | +5. **兼容性**:支持现代浏览器和移动设备 |
0 commit comments