简介Mermaid.js v10.6.1 是面向前端开发与文档编写的 JavaScript 图表渲染库开发者只需按简洁文本语法描述即可自动生成流程图、序列图、甘特图、类图等专业图表。该压缩包内含 1 个 mermaid.min.js 文件体积仅 851KB无需后端服务或外网依赖可直接引入本地项目实现离线图表渲染适合网络受限或注重数据隐私的环境。已有 510 位用户学习下载常用于快速原型设计、技术文档配图、数据分析展示等场景。包内为压缩后的稳定版示例经过版本优化与 bug 修复具备较好的兼容性与渲染性能将其部署到网页或应用程序中即可调用 Mermaid 的核心能力完成图表创建、主题定制和交互配置大大降低图表绘制门槛提升开发与协作效率。1. 流程图可视化不一定要拖拽画布v10.6.1.min.js 用一个单文件渲染工具搞定流程图可视化在 Web 端通常分成两类做法一类是拖拽画布应用另一类是「给配置出图」的渲染工具。后者里JavaScript 生态中 Mermaid 的 v10.6.1.min.js 是被验证过很稳的选择之一一个压缩后的单文件script 标签引入把接近 Markdown 的文本交给它就能得到可交互的 SVG 流程图。它解决的是改图成本——改字符串就能改图不用重新拖节点、不用手算坐标这个特性在文档系统和低代码平台里价值极高。这套方案适合文档系统生成架构图、低代码平台的流程编排、运维工单里的依赖关系图。它不追求画布拖拽的强交互更看重配置快、渲染稳、样式能跟着主题走。前端新手半小时能跑通熟手也能在初始化参数和事件绑定上做出可控的成品。我先后在模拟项目X和某跨平台系统里用它替换了两套手写 SVG 的流程渲染最大的体会是文本驱动确实省事但安全级别、字体栈和重复渲染这三个点不提前处理生产环境迟早翻车。下面的内容按「原理 → 最小运行 → 参数调优 → 数据驱动 → 避坑 → 封装」一路讲完每一步都有能直接抄的代码。2. 渲染链路拆开看从文本语法到可交互 SVGMermaid 到底怎么工作2.1 从语法到 SVG 的四步转换render 不等于画图库Mermaid 的本质不是绘图库而是「语法编译器 布局引擎 SVG 生成器」的组合。我们写的 flowchart 文本先经过词法和语法解析变成一棵内部 ASTAST 再交给 flowchart 专用的布局引擎做分层布局算出每个节点的坐标和每条边的路径最后把布局结果输出为 SVG 字符串颜色、字体、连线风格全部由主题变量控制。整个过程里我们没有直接操作坐标的机会这就是它能做到「改文本即改图」的根本原因。v10.6.1 这条线的关键变化在 API 形态上。v9 时代 render 是同步的通过回调拿结果v10 全面改成 Promisemermaid.render(id, text) 返回一个 Promiseresolve 出来的是包含 svg 字符串和 bindFunctions 的对象。这个细节让很多老教程直接失效如果你在网上搜到 v9 的写法照搬到 v10 大概率拿不到结果。这也是我坚持在项目里固定到 v10.6.1.min.js 这个具体构建的原因——10.x 后续小版本 API 没大动但固定文件名能避免依赖缓存拉到行为不一致的新构建。v10.6.1 对外暴露的全局方法实际高频使用的只有四个mermaid.initialize 负责全局配置mermaid.parse 负责校验语法mermaid.render 负责单段文本出 SVGmermaid.run 负责批量扫描页面上已有的 .mermaid 节点。run 和 render 功能看起来重叠分工其实很清楚run 适合页面加载时一键扫描render 适合动态数据场景下手动指定一段文本。日常开发里我几乎只用 render因为动态页面居多startOnLoad 扫描不到后插入的内容这是很多人第一次接入时踩到的隐性坑。为什么强调「单文件」因为很多团队的项目是在内网环境或离线部署的没有包管理器的网络权限。一个 mermaid.min.js 放进静态资源目录就能用不依赖构建工具、不依赖 CDN 可用性。这也是我后来在多个项目里坚持走 script 标签路线的原因可复现、可离线、可控版本比引入一堆 ESM 依赖更省心。2.2 用 script 标签加载 v10.6.1.min.js跑通第一张流程图最小运行方式是把 mermaid.min.js 放到本地 lib 目录一个 HTML 里直接 script 引入再写一段 flowchart 文本。注意 v10 的 mermaid.min.js 是自带全局变量的构建加载后挂在 window.mermaid 上不需要 import。下面的例子是「声明式」跑法适合页面加载时就把图渲染好!DOCTYPE html html langzh-CN head meta charsetUTF-8 script src./lib/mermaid.min.js/script /head body pre classmermaid graph TD A[需求评审] -- B[原型设计] B -- C{开发排期} C -- 通过 -- D[进入开发] C -- 不通过 -- B /pre script mermaid.initialize({ startOnLoad: true }); /script /body /htmlstartOnLoad: true 是关键参数它让 mermaid 在 DOMContentLoaded 之后扫描整个文档找到所有 class 为 mermaid 的元素读取文本内容渲染成 SVG并替换掉原元素。用 pre 而不是 div是为了保住文本的原始空格和换行避免流程图文本被 HTML 解析器吃掉缩进。如果你用 div建议把文本经 JS 字符串注入不要直接写在标签中间——小于号和括号在 HTML 里会被解析成标签结构造成语法错乱这是声明式写法最常见的翻车点。声明式跑法只适合内容写死在页面上的场景。业务里更多是「拿到一段文本再渲染」那就得用 v10 推荐的手动调用方式这也是我把 mermaid.render 单独拎出来的原因async function renderInto(box, diagramText) { const { svg, bindFunctions } await mermaid.render(flowRoot, diagramText); box.innerHTML svg; bindFunctions?.(box); }render 的第一个参数是渲染 id它会写进 SVG 的 id 属性页面内必须唯一重复 id 会让后续渲染直接 reject。第二个参数是 mermaid 语法文本。返回的 svg 是一段完整字符串必须由我们手动插入容器bindFunctions 是可选绑定函数语法里如果写了 click 节点事件不调用它绑定到 DOM 上点击回调永远不会触发。注意 render 之前必须执行过一次 mermaid.initialize哪怕只是空配置对象否则手动配置和内置默认值可能互相打架出现「本地正常、生产异常」的怪象。提示script 标签建议放在 head 里、页面内容之前。startOnLoad 依赖 DOMContentLoaded脚本放 body 尾部虽然也能跑但遇到渲染内容多、页面重的场景扫描时机和用户可见内容的时间差会明显拉长。3. 配置与 API 调优v10.6.1 的 initialize 参数、动态渲染和事件绑定3.1 initialize 关键参数theme、securityLevel、flowchart 子项initialize 是 Mermaid 的唯一全局配置入口必须在任何 render 之前调用一次。它的参数很多但对流程图渲染真正有影响的就几个下面这张表建议收藏参数默认值作用与场景themedefault主题预设default、neutral、dark、forest、base要自定义颜色就选 basestartOnLoadtrue是否自动扫描 .mermaid 节点动态页面建议 false避免和手动 render 重复securityLevelstrict安全级别strict 禁用 HTML 标签渲染loose 放行suppressErrorRenderingfalse渲染失败时是否隐藏错误 SVG调试期别关错误图直接暴露问题logLevelinfo日志级别生产环境设 error 减少控制台噪音flowchart.curvebasis连线曲线算法basis、linear、monotoneX 三类够用flowchart.nodeSpacing50同一层节点的横向间距flowchart.rankSpacing50层与层之间的纵向间距themeVariables.fontSize16px全局字号中文场景经常要配合 fontFamily 一起改下面这段配置是我在多个项目里沉淀下来的「中文业务系统基础模板」。核心思路是主题固定为 base颜色全部走 themeVariables因为 default 主题的颜色是给英文文档设计的放到中文后台里对比度常常不够mermaid.initialize({ startOnLoad: false, theme: base, logLevel: error, securityLevel: strict, suppressErrorRendering: false, flowchart: { useMaxWidth: true, htmlLabels: false, curve: basis, nodeSpacing: 50, rankSpacing: 50, padding: 12 }, themeVariables: { fontFamily: Noto Sans CJK SC, WenQuanYi Micro Hei, sans-serif, fontSize: 14px, primaryColor: #f8fafc, primaryBorderColor: #94a3b8, primaryTextColor: #1e293b, lineColor: #64748b, edgeLabelBackground: #ffffff } });flowchart.htmlLabels 在 strict 安全级别下会被强制设为 false显式写出来是为了让后来维护的人看懂节点标签一律走纯 SVG 文本渲染、 这类 HTML 标签一律不生效。想用 HTML 标签换行或插图只能把 securityLevel 放开到 loose代价是标签内容会被当 HTML 解析存在注入风险。我的建议是流程图内容来自接口而非用户输入时才考虑 loose否则保持 strict 最稳。themeVariables 里的 fontFamily 是中文渲染的命门不设它标签里的中文在某些 Linux 服务器浏览器上会退化成方块字这个问题在 5.2 会再展开。注意initialize 是全局配置同一页面只调一次。如果因为业务需要二次调用后一次会整体覆盖前一次的配置对象而不是合并。很多人以为改一个字段就能增量更新结果改了 theme 之后 flowchart 里的自定义项全部回默认就是这个原因。3.2 动态渲染与事件绑定SVG 是字符串交互要自己接流程图可视化如果只输出静态图价值少了一半。业务里常见的诉求是「点节点跳详情」或者「点节点改高亮状态」。Mermaid 的 click 语法可以给节点挂动作v10 里动作要借助 bindFunctions 手动接到 DOM 上这一步是新手最容易漏的const diagramText graph LR A[打开订单详情]:::hot B[同步库存]:::cold A -- B click A callDetail classDef hot fill:#fef3c7,stroke:#f59e0b classDef cold fill:#e0f2fe,stroke:#0ea5e9 ; function callDetail() { console.log(node A clicked); } const { svg, bindFunctions } await mermaid.render(orderFlow Date.now(), diagramText); const wrap document.getElementById(flow-wrap); wrap.innerHTML svg; bindFunctions?.(wrap);click A callDetail 这行的含义是把 A 节点的点击事件绑定到名为 callDetail 的全局函数。render 返回的 bindFunctions 必须在 SVG 插入 DOM 之后、以包含 SVG 的容器为参数调用一次Mermaid 才能把内部 onclick 和你定义的函数接上。这里的事件是 Mermaid 生成节点时自带的和普通 DOM 事件委托不冲突——你仍然可以在容器上再加自己的 click 监听通过命中节点内部的 class 名来做高亮、气泡这类交互。securityLevel 为 strict 时纯函数回调不受影响但别在回调里拿用户提供的 HTML 拼接 innerHTML 进页面那等于自己把安全机制绕开了。render 生成的 SVG 节点默认带一套 class 命名比如 node rect、edgePath、edgeLabel 这些。想做统一风格但不想改 JS 配置时页面 CSS 直接覆盖这些 class 是最省事的路子。缺点是和 Mermaid 内部结构耦合升级版本时 class 名变了样式会失效。我一般会挑不会变的结构性 class 来做覆盖颜色类一律走 themeVariables这样升级风险和样式成本都能接受。3.3 错误可视化与调试把失败留给你看不少人在渲染失败时看到的是白屏加一条控制台红字然后开始怀疑人生。v10 有个贴心的默认行为渲染失败时把错误渲染成一段红色 SVG 插回容器上面直接写着出错的行和列。这就是 suppressErrorRendering 必须保持 false 的原因。我见过某个团队把它设成 true 之后线上流程图偶发失败直接白屏连错误提示都没有排查了三个小时才发现是接口返回了一段带换行符的脏数据。把错误留给你看是渲染工具该有的职业素养。如果你要的是「全站换肤」base 主题配合 themeVariables 只够改颜色。想改节点圆角、阴影这类结构样式得在 themeVariables 之外再注入 themeCSS或者在页面 CSS 里覆盖 .node rect 的 rx 属性。两种方式我都用过结论是结构样式走外部 CSS颜色样式走 themeVariables各管一摊不要混在一个配置里写否则下次改配色时一堆样式代码互相覆盖改起来特别痛苦。4. 把业务数据画成流程图flowchart 语法子集与 JSON 生成 mermaid 文本的映射4.1 语法子集节点形状、方向、子图和 classDef 覆盖八成需求Mermaid 的 flowchart 语法远比想象中少。记全所有形状没有性价比真正高频的子集是[] 表示矩形节点() 表示圆角节点{} 表示判断节点subgraph 表示分组classDef 定义样式类click 挂事件。方向声明只有 graph TD从上到下和 graph LR从左到右两种常用。下面这段是贴近真实业务的模板建议直接照着改const orderFlowSrc flowchart TB subgraph S1[下单域] direction TB A(创建订单) -- B[支付回调] B -- C{校验结果} end subgraph S2[履约域] D[生成配送单] -- E[调度分配] end C -- 成功 -- D C -- 失败 -- F[补偿回滚]:::err classDef err fill:#fee2e2,stroke:#ef4444,color:#b91c1c ;subgraph 的关键在于子图 ID 后面跟一个带方括号的显示标题比如 subgraph S1[下单域]这样分组框上能显示中文标题否则只显示 S1 这个内部 ID。direction TB 写在 subgraph 内部用来覆盖全局方向——不写的话子图内部连线会跟着全局方向走布局会变得很拧巴。classDef 定义样式类后用 :::err 挂在节点 ID 后面相当于给新生成的 SVG 节点打类名后续可以用外部 CSS 继续覆盖。新手常有的困惑是标签文本里的空格、括号、引号到底要不要转义。Mermaid 的规则是方括号内的文本会做一层文本解析英文引号建议直接用中文引号或去掉小于号和大于号建议写成实体。这些不处理不一定会报错但可能让节点显示残缺属于典型的「不报错但结果不对」。我一般会在生成器函数里统一做转义见下一节绝不在业务代码里手写转义。为什么推荐子图和 classDef 这种组合而不是一个长链条因为分层布局引擎对「同层节点数」很敏感一个流程里同级节点超过 6 个SVG 就会变得很宽阅读体验崩坏。subgraph 能强制切分层级classDef 能把异常节点用颜色明显区分出来这两样组合起来一张 30 节点的流程图也能保持可读性。4.2 接口 JSON 映射成 mermaid 文本一个安全的生成器函数实际项目里流程图很少是手写文本更多时候来自接口后端返回节点数组和边数组前端负责拼装。拼装函数最要紧的不是美观是转义和安全。下面这个生成器我用了两年改过三轮对中文、英文引号、尖括号都稳function buildFlowText(nodes, edges) { const lines [flowchart TD]; const safeLabel (s) [${String(s) .replace(//g, amp;) .replace(//g, lt;) .replace(//g, gt;) .replace(//g, quot;)}]; for (const n of nodes) { lines.push( ${n.id}${safeLabel(n.label)}); } for (const e of edges) { const edgeLabel e.label ? |${e.label}| : ; lines.push( ${e.from} --${edgeLabel} ${e.to}); } return lines.join(\n); }safeLabel 的顺序不能乱先转 成 再做 、 和引号的转义。顺序反了后续转义出来的 会被二次转义成 lt;节点里就会出现乱码实体。edges 的 label 如果包含竖线字符会破坏 |xxx| 语法生成前最好过滤掉竖线。节点 ID 不建议直接用后端主键因为 Mermaid 的节点 ID 不允许有空格和特殊符号我用 n_001 这种带前缀的编号做映射渲染前后再做一层 ID 字典把业务主键和 mermaid ID 解耦。生成文本之后渲染前先做一次语法校验是值得养成的习惯。v10 里 mermaid.parse 是异步方法返回 Promise语法错误时 reject错误对象里带行号和片段async function safeRender(box, nodes, edges) { const text buildFlowText(nodes, edges); try { await mermaid.parse(text); } catch (err) { console.error([flow] parse 失败行号, err.message); box.innerHTML p stylecolor:#dc2626流程图数据异常请检查节点与连线。/p; return; } const { svg, bindFunctions } await mermaid.render(flow Date.now(), text); box.innerHTML svg; bindFunctions?.(box); }parse 抛出的错误带行号和片段err.message 里的内容用于定位足够用但别直接展示给终端用户那会把 Mermaid 的内部语法结构曝光出去。给用户一段业务文案把细节写进 console这是渲染工具接入时的通用做法。校验通过再 render能避免一半以上的「渲染失败却不知道哪条边出了问题」的排查成本尤其当节点来自接口、脏数据不可避免时这一步能省下大量联调时间。5. 流程图渲染常见问题与避坑五个让 Mermaid 翻车的真实现场5.1 startOnLoad 白屏全局 mermaid 被后加载的版本覆盖现象页面里引了 v10.6.1.min.js也写了 .mermaid 节点startOnLoad 设了 true打开页面却一片空白控制台没有任何报错。原因页面上同时存在两套 Mermaid 资源。常见于工程打包时依赖自动引入了一份业务代码又手动 script 引入了一份后加载的覆盖了 window.mermaid也可能反过来先加载的实例已经把 DOMContentLoaded 监听占住了后加载的又不接管。两套资源互相抢全局变量渲染链路就断了。解决全局只保留一份 mermaid.min.js用 v10.6.1.min.js 固定文件名锁版本打包工具里把 mermaid 设为 external从 index.html 统一引入。排查时在控制台执行 Object.keys(window.mermaid)看实际挂载的是不是预期构建。这个坑最气人的地方在于不报错所以排查顺序里第一个就要排除全局变量被覆盖。5.2 中文全部显示成方块字体栈没有中文字体兜底现象节点文本里的中文显示成豆腐块英文和数字完全正常。原因Mermaid 默认主题的 fontFamily 是一串西文字体栈中文在大多数操作系统里匹配不到字体回退失败后就画成了方块。解决在 themeVariables 里显式设置 fontFamily用 Noto Sans CJK SC, WenQuanYi Micro Hei, sans-serif 这类带中文字体的栈。注意末尾一定要有 sans-serif 兜底避免某个环境里第一个字体缺失就直接不渲染。这个配置必须在 initialize 阶段写入渲染完成后改 CSS 是不会生效的因为 SVG 内的文本样式由主题变量在生成那一刻决定这点很多人反复踩。5.3 节点里想换行、放图片却不生效securityLevel 和 htmlLabels 联动现象label 里写了或者渲染出来要么是纯文本原样显示要么直接报错。原因securityLevel 默认 strict强制 flowchart.htmlLabels 为 false所有 HTML 标签类语法都不参与解析。strict 的设计意图是防止标签内容被当作 HTML 执行把注入面掐掉。解决先问内容来源。如果流程图文本完全由后端生成、不受前端用户控制可以把 securityLevel 改为 loose 并显式设置 flowchart.htmlLabels: true。如果只想换行还有一个更稳的办法把 label 拆成多行节点或者用子图把长文本切成多段不用 HTML 也能完成排版。我的项目里最终都选了后者因为保持 strict 不换安全配置运维成本最低。5.4 隐藏容器里渲染完展开后 SVG 挤成一团现象流程图放在折叠面板、Tab 标签页或弹窗里渲染时容器 display:none展开后 SVG 宽度等于 0节点全部挤在左上角。原因渲染时容器没有可用宽度布局引擎按容器的可用宽度计算宽度为 0 时所有节点只能竖着堆叠。解决把渲染时机推迟到容器可见之后。常见做法是容器第一次展开时再调用 render用 flag 防止重复渲染如果必须在隐藏状态预渲染至少给容器一个占位宽度用 visibility:hidden 而不是 display:none前者仍然占据布局空间。flowchart.useMaxWidth 保持 true 能让 SVG 在大容器里自适应但它救不了渲染瞬间宽度为 0 的情况这是两个层次的问题。5.5 动态更新时事件叠加同样的 click 越点越乱现象用 render 更新流程图几次后点击某个节点回调连触发多次或者每次更新后旧图还残留在页面上。原因常见于没有清理旧 SVG 就继续往容器里 append 新 SVG容器累积了多层节点或者每次都传同一个 render idMermaid 内部对重复 id 的处理不可预期。解决render 前先把容器 innerHTML 清空render id 用时间戳或自增计数器保证唯一。事件绑定跟着新 SVG 走旧节点被移除后监听器会被垃圾回收所以只要做到「清空后再插入」这一个纪律事件叠加问题就消失了。我在第 6 章里封装的组件核心就是固化这两个动作建议直接复用。6. 封装一个可销毁的渲染组件初始化一次、按需替换、事件不泄露最后给一个可以直接抄的封装。要点是全局只调一次 mermaid.initialize组件实例负责「清空 → render → 绑定事件」这个固定序列并提供销毁方法用于 SPA 切页或弹窗关闭时释放容器。class FlowRenderer { constructor(container, config {}) { this.box container; this.config config; this.seq 0; } async render(text) { const id flow Date.now() _ this.seq; const { svg, bindFunctions } await mermaid.render(id, text); this.box.innerHTML ; this.box.innerHTML svg; bindFunctions?.(this.box); } async update(text) { await this.render(text); } destroy() { this.box.innerHTML ; this.seq 0; } }用法上只需要在应用启动处执行一次 mermaid.initialize({ startOnLoad: false, ... })之后 new FlowRenderer(box) 再调 render(text)。这里刻意把 parse 校验放在组件外面校验属于数据层职责组件只管把「已经合法的文本」画出来职责分得越干净后续接 React、接原生都顺手。如果你用框架把组件包成自定义元素或普通类都行内部逻辑不用改。如果流程图数量多、节点超过一两百个建议给 render 加并发控制或者先对文本做精简去掉多余 classDef、把长 label 截断到 20 字。节点太多时再漂亮的曲线也是阅读灾难这属于产品问题不是渲染工具能解的。最后说一个我的习惯每次升级 Mermaid 版本先把线上流程图截图跑一遍对比回归再看 changelog 里 flowchart 相关条目。v10.6.1 这个构建我用了大半年API 稳定坑都集中在配置语义上而不是库本身的 bug希望你接入时能少走这五关希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?