VitePress & Markmap
虽然 mermaid 也支持思维导图,但是功能较弱,而且也比较乱。还是比较喜欢 markmap 这种样式的,于是调查了下如何在 VitePress 中使用 markmap。
因为前端不是太熟,感觉写法不够优雅,不过勉强能用。
下面是具体的步骤,仅供参考。
安装 markmap-lib 依赖:
bash
npm i -D markmap-lib
在 config.mts 文件中添加 Markdown 插件配置:
ts
import { defineConfig } from 'vitepress'
import { Transformer } from 'markmap-lib'
const transformer = new Transformer();
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
export default defineConfig({
title: "My Awesome Project",
description: "A VitePress Site",
markdown: {
config: (md) => {
const temp = md.renderer.rules.fence.bind(md.renderer.rules);
md.renderer.rules.fence = (tokens, idx, options, env, slf) => {
const token = tokens[idx];
if (token.info === 'mindmap') {
try {
const { root, _ } = transformer.transform(token.content.trim());
return `<svg class="markmap-svg" data-json='${escapeHtml(JSON.stringify(root))}'></svg>`;
} catch (ex) {
return `<pre>${ex}</pre>`
}
}
return temp(tokens, idx, options, env, slf)
};
}
},
})
在自定义主题中添加渲染 Markmap 的处理:
ts
// .vitepress/theme/index.js
import { onMounted, watch, nextTick } from 'vue';
import DefaultTheme from 'vitepress/theme'
import { onContentUpdated, useRoute } from 'vitepress';
import type { Theme as ThemeConfig } from 'vitepress'
import { Markmap } from 'markmap-view'
// 引入自定义样式文件
import './custom.css'
// 渲染思维导图
function renderMindmap() {
const mindmaps = document.querySelectorAll('.markmap-svg');
for (const mindmap of mindmaps) {
const dataJson = mindmap.getAttribute('data-json');
if (mindmap instanceof SVGElement && dataJson) {
if(mindmap.children.length > 0) continue;
const mp = Markmap.create(mindmap, {
autoFit: true,
pan: false,
zoom: false,
}, JSON.parse(dataJson));
// 重新设置 SVG 的高度
setTimeout(() => {
const width = mp.state.rect.x2 - mp.state.rect.x1; // SVG 的实际宽度
const height = mp.state.rect.y2 - mp.state.rect.y1; // SVG 的实际高度
const aspectRatio = height / width; // 高宽比
// 定义一个子方法用于重新设置 mindmap 的高度
function setMindmapHeight(mindmap: SVGElement, aspectRatio: number) {
const realHeight = mindmap.clientWidth * aspectRatio + 30;
mindmap.style.height = `${realHeight}px`;
mp.fit()
}
// 注册 window 的窗口大小变动事件
window.addEventListener('resize', () => {
setMindmapHeight(mindmap, aspectRatio);
})
// 初始设置时调用子方法
setMindmapHeight(mindmap, aspectRatio);
}, 0)
}
}
}
export const Theme: ThemeConfig = {
extends: DefaultTheme,
setup() {
onContentUpdated(() => {
renderMindmap();
});
},
}
export default Theme
示例
markdown
```mindmap
# root
## child1
- child3
## child2
- child3
```
markdown
```mindmap
## Links
- <https://markmap.js.org/>
- [GitHub](https://github.com/gera2ld/markmap)
## Related
- [coc-markmap](https://github.com/gera2ld/coc-markmap)
- [gatsby-remark-markmap](https://github.com/gera2ld/gatsby-remark-markmap)
## Features
- links
- **inline** ~~text~~ *styles*
- multiline
text
- `inline code`
- `<video>`
```
2025-06-13 追记
- 修复了节点行内代码中包含
<>
HTML 标签时无法显示的问题; - 增加了在页面大小变动时自动调整的处理;