Skip to content

工作原理

这个包出现的原因很直接:原始 Mermaid HTML 只解决了第一段工作,真正的文档站还需要挂载 重渲染 导出 缩放 全屏 与路由切换后的生命周期控制

它解决了什么

markdown-it 只负责把 fence 变成 HTML,不负责浏览器状态,不负责路由切换后的再初始化,也不会自带工具栏

markdown-it-mermaid-enhanced 把这部分工作拆成两段

  1. markdown-it 插件把 Mermaid fence 改写成面向运行时的 wrapper
  2. 浏览器运行时把 wrapper 升级成可交互的图表壳层

渲染管线

Loading diagram…

主包架构

Loading diagram…

这样拆分之后,编译期 HTML 生成 浏览器交互 共享配置 与 VitePress 接入边界会更清晰

工作流程图

Loading diagram…

关键边界在于 markdown-it 侧只负责序列化状态,运行时侧才负责异步渲染与交互状态

插件实际输出了什么

每张图都会变成一层 wrapper,核心元素有三块

  • 隐藏的 <pre>,负责保留原始 Mermaid 源码
  • data-mermaid-config,负责携带解析后的配置
  • 默认工具栏,负责缩放 复制 导出 与全屏

这套结构的意义在于原地重渲染,而不是整块替换 DOM

运行时模型

浏览器运行时会按需把 wrapper 升级成 Vue 应用

  • initMermaidIt() 查找未挂载 wrapper,并只挂载一次
  • rerenderMermaidIt() 重新读取 wrapper 状态,再原地刷新
  • 缩放状态与 wrapper 绑在一起,所以纯配置刷新时可以保住当前视口

运行时设计图

Loading diagram…

每个 wrapper 都会保留一份很小的运行时状态,这样重渲染时可以原地替换 SVG,而不是销毁整个宿主节点

为什么路由切换需要额外处理

单页文档框架切换页面时不会重载整个浏览器环境,所以新的 wrapper 需要在路由切换后重新发现并挂载

VitePress helper 的工作就是等待 DOM 更新 重试 wrapper 发现 然后再执行挂载

关键源码

  • src/markdown-it/plugin.ts 负责 fence 解析与 wrapper HTML
  • src/runtime.ts 负责公开运行时入口
  • src/runtime/MermaidWrapperRuntime.vue 负责交互壳层
  • src/runtime/core.ts 负责渲染 导出 SVG 挂载 与缩放控制
  • src/vitepress.ts 负责把运行时接入 VitePress 路由