在技术博客写作中,思维导图是一个非常有用的工具,它可以帮助我们更清晰地展示知识结构和概念关系。本文将介绍如何在 Hexo 博客中集成 Markmap,让你能够直接在 Markdown 文件中创建交互式思维导图。

什么是 Markmap?

Markmap 是一个将 Markdown 格式的文本转换为思维导图的开源工具。它允许我们使用熟悉的 Markdown 语法来创建漂亮的、交互式的思维导图。

实现方案

1. 安装必要依赖

首先,我们需要安装 uuid 包,这是用来给我们每一个思维导图生成一个唯一的 ID:

1
npm install uuid --save

2. 创建自定义标签插件

scripts/markmap_tag.js 中创建自定义标签:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Markmap Tag Plugin for Hexo
*/
"use strict";

const { v4: uuidv4 } = require("uuid");

hexo.extend.tag.register(
"markmap",
function (args, content) {
const id = uuidv4();

return `
<div class="markmap" id="markmap-${id}">
<script type="text/template">
${content}
</script>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const template = document.querySelector('#markmap-${id} script[type="text/template"]');
if (template) {
const content = template.textContent;
window.markmap.autoLoader.renderString(content, null, document.querySelector('#markmap-${id}'));
}
});
</script>
`;
},
{ ends: true }
);

3. 添加样式

创建 source/css/markmap.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* Markmap Styles */
.markmap {
width: 100%;
height: 500px;
margin: 20px 0;
border: 1px solid #eaeaea;
border-radius: 5px;
overflow: hidden;
}

.markmap svg {
width: 100%;
height: 100%;
}

/* 响应式设计 */
@media (max-width: 768px) {
.markmap {
height: 400px;
}
}

@media (max-width: 480px) {
.markmap {
height: 300px;
}
}

4. 更新主题配置

在主题配置文件中添加必要的资源引用:

1
2
3
4
inject:
head:
- <link rel="stylesheet" href="/css/markmap.css">
- <script src="https://cdn.jsdelivr.net/npm/markmap-autoloader@0.18"></script>

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{% markmap %}

- 技术栈
- 前端
- Vue.js
- React
- Angular
- 后端
- Node.js
- Python
- Go
- 数据库
- MySQL
- MongoDB
- Redis

{% endmarkmap %}

工作原理

1. Hexo 插件系统

  • Hexo 提供了强大的插件系统,允许我们通过 hexo.extend API 来扩展功能
  • 我们使用了 hexo.extend.tag 来注册自定义标签,这是 Hexo 提供的标准扩展点之一

2. 标签插件的工作原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
hexo.extend.tag.register(
"markmap",
function (args, content) {
const id = uuidv4(); // 生成唯一ID

return `
<div class="markmap" id="markmap-${id}">
<script type="text/template">
${content}
</script>
</div>
...
`;
},
{ ends: true }
);
  • 当 Hexo 解析到 markmap 标签时,会调用这个注册的函数
  • content 参数包含了标签之间的所有内容(你的 markdown 结构)
  • {ends: true} 表示这是一个闭合标签(需要 endmarkmap 结束)

3. Markmap 库的渲染过程

  • Markmap 库使用 markmap-autoloader 自动处理 markdown 到思维导图的转换
  • 转换过程:
    1. Markdown 文本被解析成层级结构
    2. 层级结构被转换为 SVG 路径
    3. SVG 被渲染到页面上,并添加交互功能

4. HTML 结构设计

1
2
3
4
5
<div class="markmap" id="markmap-${id}">
<script type="text/template">
${content}
</script>
</div>
  • 使用 script type="text/template" 来存储原始 markdown
  • 每个思维导图都有唯一 ID,避免页面上多个图表互相干扰

5. JavaScript 初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
document.addEventListener("DOMContentLoaded", () => {
const template = document.querySelector(
'#markmap-${id} script[type="text/template"]'
);
if (template) {
const content = template.textContent;
window.markmap.autoLoader.renderString(
content,
null,
document.querySelector("#markmap-${id}")
);
}
});
  • 等待页面加载完成
  • 获取模板中的 markdown 内容
  • 使用 markmap 库渲染思维导图

6. 样式控制

1
2
3
4
5
6
7
8
.markmap {
width: 100%;
height: 500px;
margin: 20px 0;
border: 1px solid #eaeaea;
border-radius: 5px;
overflow: hidden;
}
  • 提供响应式布局
  • 确保思维导图在各种屏幕尺寸下都能正常显示

7. 主题集成

  • 在主题配置中注入必要的 CSS 和 JavaScript
  • 确保资源在正确的时机加载