VitePress实现MarkMap的兼容
什么是 MarkMap?
MarkMap 是一个将 Markdown 文件实时渲染为思维导图的工具。它基于 D3.js 实现,支持将 Markdown 的标题结构 (#
、##
、###
等) 转换成树形结构的节点,从而直观展示内容的层级关系。
与传统思维导图工具不同,MarkMap 不需要你额外绘图、拖拽,只需写出规范的 Markdown,就能“一键导图”。
官方仓库
GitHub:https://github.com/markmap/markmap
核心特性
- 🚀 零配置上手:直接使用 Markdown 语法,无需学习新的格式。
- ✨ 即时预览:支持 VS Code 插件 / CLI 工具 / Web 页面多种方式预览。
- 📦 开箱即用:支持导出为 HTML 文件嵌入页面。
- 🧠 结构清晰:非常适合整理脑图、会议记录、知识点。
MarkMap 是如何工作的?
MarkMap 核心流程可以简化为以下三步:
- 解析 Markdown:使用
markdown-it
将 Markdown 转换为 AST。 - 生成树结构:从 Markdown 的标题层级 (
#
,##
,###
) 构建树状图节点。 - 可视化渲染:利用 D3.js 将节点绘制成 SVG 图形并绑定动画交互。
安装与使用
方式一:通过 VS Code 插件
最简单的方式就是安装官方插件 markmap-vscode:
- 打开一个
.md
文件 - 按下
Ctrl+Shift+P
,选择Markmap: Open Preview
- 即可看到实时导图
方式二:命令行工具
npm install -g markmap-cli
markmap your-file.md
运行后会生成一个独立 HTML 文件(含 JS 脚本),可直接打开或部署。
方式三:Web 工具
访问 https://markmap.js.org/repl,粘贴 Markdown 内容即可预览导图。
实战场景
场景 | 使用价值 |
---|---|
📚 学习笔记 | 把课程内容层层拆解,快速构建知识体系 |
🧩 项目架构 | 理清业务模块、依赖关系、开发路径 |
🧠 头脑风暴 | 快速草拟创意、评估方案可行性 |
📝 技术文档 | 辅助阅读冗长文档,提高可读性 |
限制与注意事项
- 内容限制:仅支持标题 (
#
) 层级内容,正文段落不渲染为节点。 - 自定义样式有限:虽然可以用插件扩展,但不如专业导图软件灵活。
- 交互有限:拖拽、折叠节点等功能有限,更多偏向静态展示。
与其他工具对比
工具 | 特点 | 编辑效率 | 交互能力 | 可定制性 |
---|---|---|---|---|
MarkMap | Markdown 驱动 | ✅ 快速 | ❌ 较弱 | ⚠️ 有限 |
XMind | 专业导图工具 | ❌ 拖拽繁琐 | ✅ 强 | ✅ 高 |
Whimsical / Miro | 多协作形式 | ✅ 可拖拽 | ✅ 支持团队协作 | ✅ 高 |
Markmap 思维导图测试
下面是一个 markmap 代码块的示例,用于测试插件是否能正确渲染:
如何在 VitePress 中使用 MarkMap
创建插件文件
首先你要有一个插件配置文件: markmapPlugin.js
export function markmapPlugin(md) {
const fence = md.renderer.rules.fence.bind(md.renderer.rules);
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
const token = tokens[idx];
if (token.info.trim() === 'markmap') {
// 对内容进行 encodeURIComponent 编码,避免注入和解析错误
const content = encodeURIComponent(token.content);
return `<Markmap :content="decodeURIComponent('${content}')" />`;
}
return fence(tokens, idx, options, env, self);
};
}
引入插件
然后你要在你的vitepress配置文件中引入这个插件:通常这个文件的路径是 .vitepress/config.js
import { markmapPlugin } from './markmapPlugin';
export default {
markdown: {
markdown: {
config(md) {
markmapPlugin(md)
},
},
},
}
编写组件
除此之外你还要编写一个Markmap.vue组件,用于渲染 MarkMap的内容
<script setup>
import { ref, onMounted, nextTick } from 'vue'
import { Transformer } from 'markmap-lib'
import { Markmap } from 'markmap-view'
const props = defineProps({
content: String
})
const svgRef = ref()
const transformer = new Transformer()
onMounted(() => {
if (typeof window === 'undefined') return;
const { root } = transformer.transform(props.content)
Markmap.create(svgRef.value, {}, root)
})
const exportAsJpg = async () => {
const svg = svgRef.value
if (!svg) return
// 克隆SVG节点,避免污染原始DOM
const clonedSvg = svg.cloneNode(true)
// 计算宽高
const width = svg.clientWidth || 800
const height = svg.clientHeight || 500
// 创建canvas
const canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
// 将SVG序列化为字符串
const serializer = new XMLSerializer()
let svgString = serializer.serializeToString(clonedSvg)
// 兼容处理:加上xmlns属性
if (!svgString.includes('xmlns="http://www.w3.org/2000/svg"')) {
svgString = svgString.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"')
}
// 创建图片对象
const img = new window.Image()
img.onload = function () {
const ctx = canvas.getContext('2d')
ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, width, height)
ctx.drawImage(img, 0, 0, width, height)
const url = canvas.toDataURL('image/jpeg')
const link = document.createElement('a')
link.href = url
link.download = 'markmap.jpg'
link.click()
}
img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(svgString)))
}
</script>
<template>
<div class="relative w-full">
<svg ref="svgRef"
class="w-full h-[50vh] max-h-[500px] min-h-[200px] my-4 rounded-lg border dark:border-zinc-700 transition-all duration-300 bg-white bg-opacity-30" />
<button @click="exportAsJpg"
class="absolute top-2 right-2 px-3 py-1 bg-blue-500 text-white rounded shadow hover:bg-blue-600">导出</button>
</div>
</template>
全局注册组件
最后你要在你的vitepress配置文件中全局注册这个组件:通常这个文件的路径是 .vitepress/theme/index.js
import Markmap from './Markmap.vue'
export default {
enhanceApp({ app }) {
app.component('Markmap', Markmap)
},
}
愉快的使用吧
现在你可以在你的Markdown文件中愉快的使用markmap了
用法和就是在Markdown中插入一个代码块,并指定其语言为markmap
即可。
总结:写 Markdown 的人,值得拥有 MarkMap
MarkMap 的出现,不是为了取代传统思维导图,而是为 Markdown 创作者提供了一个“零摩擦”的思维可视化通道。对习惯用 Markdown 写作、记录的开发者、写作者、学生而言,它是一种几乎无门槛的升级方案。