- 添加 convertMermaidCodeblocks() 函数,在代码高亮前拦截 mermaid 代码块 - 支持标准 Markdown 代码块 (\\\mermaid) 渲染 - 更新 detectMermaidBlocks() 添加 mermaid-from-codeblock 选择器 - 更新 extractMermaidCode() 支持新容器类型 - 创建测试文件 test-codeblock-magic.html - 更新用户文档、开发者文档和 FAQ - 完全绕过代码高亮和 WordPress 格式化 - 支持 PJAX 页面切换 - 特殊字符和换行符正确保留
16 KiB
Mermaid 代码块魔改支持 - 需求文档
1. 项目概述
1.1 背景
当前 Argon 主题支持 Mermaid 图表渲染,但存在多个标记方式的兼容性问题:
- 标准 Markdown 代码块 (
```mermaid):被 WP-Markdown 插件和代码高亮干扰 - 容器语法 (
::: mermaid ... :::):空行导致内容截断 - Shortcode (
[mermaid]...[/mermaid]):可用但不符合 Markdown 标准
用户希望使用标准 Markdown 语法 ```mermaid,但需要绕过所有干扰。
1.2 核心问题
- WP-Markdown 插件会将
```mermaid代码块用document.write()包裹 - WordPress 的
wptexturize()会自动转换特殊字符(--→–) - 主题的代码高亮会处理 mermaid 代码块,添加行号和控制按钮
- 三方冲突导致 Mermaid 代码无法正确渲染
1.3 解决方案
魔改代码块显示:在代码高亮之前拦截 mermaid 代码块,将其转换为 Mermaid 渲染容器,完全绕过代码高亮和 WordPress 格式化。
1.4 参考实现
主题中数学公式的实现方式可以作为参考:
- MathJax/KaTeX:使用特定分隔符(
$...$、\(...\))标记数学公式 - 渲染时机:在 PJAX 加载完成后调用
MathJax.typeset()或renderMathInElement() - 不干扰代码高亮:数学公式使用特殊标记,不会被代码高亮处理
- WordPress 兼容:数学公式分隔符不会被 WordPress 自动转换
关键差异:
- 数学公式使用内联标记(
$...$),不需要代码块 - Mermaid 需要使用代码块(
```mermaid),需要在代码高亮前拦截 - 数学公式库自动扫描页面,Mermaid 需要手动检测和渲染
2. 用户故事
2.1 作为博客作者
我想要:使用标准 Markdown 语法 ```mermaid 编写流程图
以便:在原生编辑器中清晰可见,符合 Markdown 标准,无需学习特殊语法
验收标准:
- 可以使用
```mermaid代码块编写 Mermaid 图表 - 代码块不会被代码高亮处理(无行号、无控制按钮)
- 代码块会被正确转换为 Mermaid 图表
- 支持所有 Mermaid 语法(flowchart, sequence, class, state 等)
2.2 作为博客作者
我想要:Mermaid 代码中的特殊字符不被 WordPress 转换
以便:箭头符号 --> 不会变成 –>,图表能正确渲染
验收标准:
- 箭头符号
-->保持不变 - 双横线
--保持不变 - 其他特殊字符(
==,~~,::等)保持不变 - 换行符正确保留
2.3 作为博客作者
我想要:Mermaid 代码块在编辑器中显示为代码块
以便:编辑时能清晰看到代码结构,方便修改
验收标准:
- 在 WordPress 原生编辑器中显示为代码块
- 在 WP-Markdown 编辑器中显示为代码块
- 代码块有语法高亮(编辑器层面)
- 保存后前端正确渲染为图表
2.4 作为开发者
我想要:拦截逻辑在代码高亮之前执行
以便:避免代码高亮干扰 Mermaid 渲染
验收标准:
- 在
highlightJsRender()函数开始处添加预处理 - 查找所有
pre > code.language-mermaid元素 - 提取纯文本代码(不经过任何处理)
- 创建 Mermaid 渲染容器
- 替换原始代码块元素
2.5 作为开发者
我想要:支持多种 Mermaid 代码块格式
以便:兼容不同插件和编辑器生成的 HTML 结构
验收标准:
- 支持
<pre><code class="language-mermaid">格式 - 支持
<pre><code class="mermaid">格式 - 支持
<code class="language-mermaid">格式(无 pre 包裹) - 支持
<pre data-lang="mermaid">格式
3. 功能需求
3.1 代码块拦截(核心功能)
需求描述:在代码高亮之前拦截 mermaid 代码块
实现位置:argontheme.js 的 highlightJsRender() 函数开始处(第 3942 行)
参考实现:类似数学公式在 PJAX 加载后的处理方式(第 2862-2880 行)
处理流程:
- 在
highlightJsRender()函数开始处添加预处理 - 查找所有 mermaid 代码块(多种选择器)
- 遍历每个代码块
- 提取纯文本代码
- 创建 Mermaid 渲染容器
- 替换原始代码块元素
- 标记已处理(避免重复处理)
选择器优先级:
const selectors = [
'pre > code.language-mermaid', // 标准格式(最常见)
'pre > code.mermaid', // 简化格式
'code.language-mermaid', // 无 pre 包裹
'pre[data-lang="mermaid"]' // 自定义属性格式
];
实现示例:
function highlightJsRender(){
// 在代码高亮之前,先处理 Mermaid 代码块
convertMermaidCodeblocks();
// 原有的代码高亮逻辑
if (typeof(hljs) == "undefined"){
return;
}
// ...
}
function convertMermaidCodeblocks(){
// 查找所有 mermaid 代码块
const selectors = [
'pre > code.language-mermaid',
'pre > code.mermaid',
'code.language-mermaid',
'pre[data-lang="mermaid"]'
];
selectors.forEach(selector => {
document.querySelectorAll(selector).forEach(element => {
// 避免重复处理
if (element.dataset.mermaidProcessed) {
return;
}
// 提取代码
let code = element.textContent.trim();
if (!code) {
return;
}
// 创建容器
const container = document.createElement('div');
container.className = 'mermaid-from-codeblock';
container.textContent = code;
container.dataset.processed = 'true';
// 替换元素
const targetElement = element.closest('pre') || element;
targetElement.parentNode.replaceChild(container, targetElement);
});
});
}
3.2 代码提取
需求描述:从不同格式的代码块中提取纯文本代码
处理逻辑:
- 使用
textContent获取纯文本(避免 HTML 实体) - 移除前后空白字符(
trim()) - 不进行任何字符转换(保持原始内容)
- 检查代码是否为空
特殊处理:
- 如果代码块包含
<script>标签(WP-Markdown 生成),先移除 - 如果代码块被其他元素包裹,递归查找
code元素
3.3 容器创建
需求描述:创建 Mermaid 渲染容器,替换原始代码块
容器结构:
<div class="mermaid-from-codeblock" data-processed="true">
flowchart TD
A --> B
</div>
容器属性:
class="mermaid-from-codeblock":标识来源于代码块data-processed="true":标记已处理,避免重复textContent:纯文本 Mermaid 代码(不使用innerHTML)
替换逻辑:
- 使用
replaceWith()替换原始元素 - 如果原始元素在
<pre>中,替换整个<pre>元素 - 保留原始元素的位置和上下文
3.4 渲染检测
需求描述:在 Mermaid 渲染时检测新的容器类型
实现位置:argontheme.js 的 detectMermaidBlocks() 函数(第 4430 行)
参考实现:类似数学公式的自动检测机制
修改内容:
const selectors = [
'div.mermaid-shortcode', // Shortcode 格式
'div.mermaid-from-codeblock', // 代码块魔改格式(新增)
'div.mermaid', // 标准格式
'pre code.language-mermaid', // Markdown 格式(降级)
'pre[data-lang="mermaid"]', // 自定义属性格式
'code.mermaid' // 简化格式
];
优先级说明:
mermaid-from-codeblock优先级高于标准mermaid类- 避免与其他检测逻辑冲突
- 如果代码块转换失败,仍可通过降级选择器检测
3.5 代码提取适配
需求描述:在 extractMermaidCode() 函数中支持新的容器类型
实现位置:argontheme.js 的 extractMermaidCode() 函数(第 4650 行)
参考实现:类似 Shortcode 格式的处理方式
处理逻辑:
// 处理代码块魔改格式
if (element.classList.contains('mermaid-from-codeblock')) {
code = element.textContent;
this.logDebug('从代码块魔改格式提取代码');
}
提取方式:
- 直接使用
textContent获取纯文本 - 不进行任何转换或清理
- 保持与其他格式一致的处理方式
3.6 PJAX 兼容
需求描述:确保在 PJAX 页面切换后仍能正常工作
实现位置:PJAX 加载完成回调(第 2862-2890 行)
参考实现:数学公式在 PJAX 后重新渲染
处理逻辑:
- 代码块转换在
highlightJsRender()中执行 highlightJsRender()已在 PJAX 回调中调用(第 2887 行)- 无需额外修改,自动支持 PJAX
验证要点:
- PJAX 切换后,新页面的 mermaid 代码块能正确转换
- 已转换的代码块不会重复处理
- Mermaid 图表能正确渲染
4. 非功能需求
4.1 性能要求
- 拦截处理应在 10ms 内完成(单个代码块)
- 不影响页面加载速度
- 不增加额外的 HTTP 请求
4.2 兼容性要求
- 兼容 WordPress 5.0+
- 兼容 WP-Markdown 插件
- 兼容其他 Markdown 插件(Jetpack Markdown 等)
- 兼容主题的代码高亮功能
4.3 可维护性要求
- 代码逻辑清晰,易于理解
- 添加详细的注释说明
- 使用统一的命名规范
- 遵循主题现有的代码风格
4.4 调试支持
- 使用
this.logDebug()输出调试信息 - 记录处理的代码块数量
- 记录提取的代码内容(前 100 字符)
- 记录容器创建和替换过程
5. 技术约束
5.1 代码风格
- 使用 Tab 缩进
- 使用单引号
' - 使用严格相等
=== - 函数名使用驼峰命名
- 添加 JSDoc 注释
5.2 jQuery 使用
- 优先使用原生 JavaScript
- 仅在必要时使用 jQuery
- 避免混用原生和 jQuery 方法
5.3 错误处理
- 使用 try-catch 包裹关键代码
- 捕获异常后记录日志
- 不中断其他代码块的处理
- 提供降级方案
5.4 执行顺序约束(关键)
必须严格遵守以下执行顺序:
-
代码块转换(
convertMermaidCodeblocks())- 在
highlightJsRender()函数开始处执行 - 将
<pre><code class="language-mermaid">转换为<div class="mermaid-from-codeblock"> - 必须在代码高亮之前完成
- 在
-
代码高亮(
highlightJsRender())- 处理所有代码块,但跳过 mermaid 相关的
- 已有跳过逻辑(第 3963-3970 行)
- 不会处理已转换的
<div>元素
-
Mermaid 检测(
detectMermaidBlocks())- 在页面加载完成后执行
- 检测所有 Mermaid 容器(包括新的
mermaid-from-codeblock) - 提取代码并准备渲染
-
Mermaid 渲染(
mermaid.init())- 最后执行
- 将代码渲染为 SVG 图表
参考实现:
// PJAX 加载完成后的执行顺序(第 2862-2890 行)
try { waterflowInit(); } catch (err) { ... }
try { lazyloadInit(); } catch (err) { ... }
try { zoomifyInit(); } catch (err) { ... }
try { highlightJsRender(); } catch (err) { ... } // 代码高亮(包含代码块转换)
try { panguInit(); } catch (err) { ... }
// ... 其他初始化
// Mermaid 渲染在单独的地方调用
6. 测试需求
6.1 单元测试
- 测试代码块检测逻辑
- 测试代码提取逻辑
- 测试容器创建逻辑
- 测试替换逻辑
6.2 集成测试
- 测试与代码高亮的集成
- 测试与 Mermaid 渲染的集成
- 测试与 WP-Markdown 的集成
- 测试与 WordPress 的集成
6.3 浏览器测试
- Chrome 最新版
- Firefox 最新版
- Safari 最新版
- Edge 最新版
6.4 测试用例
创建测试文件 tests/test-codeblock-magic.html,包含:
- 标准 Markdown 代码块
- 多个代码块
- 嵌套代码块
- 空代码块
- 特殊字符代码块
- 多行代码块
7. 文档需求
7.1 用户文档
- 更新
docs/mermaid-usage-guide.md - 添加代码块魔改方式的说明
- 提供使用示例
- 说明优缺点
7.2 开发者文档
- 更新
docs/mermaid-developer-guide.md - 说明实现原理
- 提供代码示例
- 说明扩展方式
7.3 FAQ 文档
- 更新
docs/mermaid-faq.md - 添加常见问题
- 提供解决方案
- 说明注意事项
8. 验收标准
8.1 功能验收
- 可以使用
```mermaid代码块编写图表 - 代码块不会被代码高亮处理
- 图表正确渲染
- 特殊字符不被转换
- 换行符正确保留
8.2 性能验收
- 单个代码块处理时间 < 10ms
- 页面加载时间无明显增加
- 无额外的 HTTP 请求
8.3 兼容性验收
- 兼容 WordPress 5.0+
- 兼容 WP-Markdown 插件
- 兼容主题代码高亮
- 兼容所有主流浏览器
8.4 代码质量验收
- 代码风格符合规范
- 添加详细注释
- 无 ESLint 错误
- 无 console 错误
9. 风险评估
9.1 技术风险
- 风险:可能与其他插件冲突
- 影响:中等
- 缓解措施:添加兼容性检测,提供降级方案
9.2 性能风险
- 风险:大量代码块可能影响性能
- 影响:低
- 缓解措施:优化选择器,使用缓存
9.3 兼容性风险
- 风险:不同插件生成的 HTML 结构不同
- 影响:中等
- 缓解措施:支持多种选择器,添加降级逻辑
10. 后续优化
10.1 短期优化(1-2 周)
- 添加配置选项(是否启用代码块魔改)
- 优化性能(缓存、批量处理)
- 完善错误处理
10.2 中期优化(1-2 月)
- 支持更多 Mermaid 配置选项
- 添加编辑器预览功能
- 优化移动端显示
10.3 长期优化(3-6 月)
- 支持其他图表库(PlantUML、GraphViz 等)
- 添加图表编辑器
- 支持图表导出
11. 参考资料
11.1 主题现有实现
-
数学公式渲染(
footer.php第 36-147 行):- MathJax 3:使用
$...$和\(...\)分隔符 - MathJax 2:使用
$...$和\(...\)分隔符 - KaTeX:使用
$$...$$和$...$分隔符 - 渲染时机:页面加载完成后自动扫描
- PJAX 支持:在 PJAX 回调中重新调用渲染函数(第 2862-2880 行)
- MathJax 3:使用
-
代码高亮(
argontheme.js第 3942-4000 行):- 使用 highlight.js 库
- 处理
<pre><code>元素 - 添加行号、控制按钮、复制功能
- 跳过
.no-hljs和.mermaid类的代码块
-
Mermaid 渲染(
argontheme.js第 4430-4750 行):- 检测多种格式的 Mermaid 代码块
- 提取代码内容
- 调用
mermaid.init()渲染图表 - 支持容器语法和 Shortcode
11.2 实现对比
| 特性 | 数学公式 | Mermaid(当前) | Mermaid(魔改后) |
|---|---|---|---|
| 标记方式 | 内联分隔符 $...$ |
代码块 ```mermaid |
代码块 ```mermaid |
| WordPress 干扰 | 无(分隔符不被转换) | 有(特殊字符被转换) | 无(提前拦截) |
| 代码高亮干扰 | 无(不是代码块) | 有(被当作代码块) | 无(提前转换) |
| 渲染时机 | 页面加载后自动 | 页面加载后手动检测 | 页面加载后手动检测 |
| PJAX 支持 | 是(重新调用渲染) | 是(重新检测) | 是(重新转换+检测) |
| 编辑器可见性 | 可见(内联文本) | 可见(代码块) | 可见(代码块) |
| 标准兼容性 | LaTeX 标准 | Markdown 标准 | Markdown 标准 |
11.3 相关文档
11.2 相关代码
argontheme.js- 主题核心 JSfunctions.php- WordPress 函数style.css- 主题样式
11.3 相关 Issue
- 代码高亮干扰 Mermaid 渲染
- WordPress 自动转换特殊字符
- 容器语法空行截断问题