字
字节笔记本
2026年2月20日
Mermaid 图表绘制完全指南:从入门到精通
API中转
¥120
Mermaid 是一个基于 JavaScript 的图表绘制工具,使用类似 Markdown 的文本语法生成流程图、时序图、类图等多种图表。本文详细介绍在 VibeAny 项目中使用 Mermaid 的各种配置和最佳实践。
什么是 Mermaid
Mermaid (美人鱼) 让你用文本语法创建图表,无需复杂的绘图工具。它的核心优势:
| 特性 | 说明 |
|---|---|
| 文本即图表 | 使用类 Markdown 语法,版本控制友好 |
| 多种图表 | 流程图、时序图、类图、甘特图等 10+ 种 |
| 实时渲染 | 浏览器端动态渲染,无需后端 |
| 主题定制 | 支持多种内置主题和自定义样式 |
| 广泛集成 | GitHub、GitLab、Notion 等原生支持 |
基础使用
安装
bash
# npm
npm install mermaid
# pnpm (推荐)
pnpm add mermaid
# yarn
yarn add mermaid基本渲染
typescript
import mermaid from 'mermaid'
// 初始化配置
mermaid.initialize({
startOnLoad: true,
theme: 'default'
})
// 渲染图表
const graphDefinition = `
graph TD
A[开始] --> B{判断}
B -->|条件1| C[处理1]
B -->|条件2| D[处理2]
C --> E[结束]
D --> E
`
// 在指定元素中渲染
mermaid.render('graph-div', graphDefinition).then(({ svg }) => {
document.getElementById('graph-container').innerHTML = svg
})图表类型详解
1. 流程图 (Flowchart)
最常用的图表类型,展示流程和决策:
mermaid
graph TD
A[用户访问] --> B{是否登录}
B -->|是| C[显示首页]
B -->|否| D[跳转登录]
D --> E[输入凭证]
E --> F{验证成功}
F -->|是| C
F -->|否| G[显示错误]
G --> E语法详解:
mermaid
graph TD %% TD=从上到下, LR=从左到右
A[矩形节点] %% [] 表示矩形
B(圆角矩形) %% () 表示圆角矩形
C[[子程序]] %% [[]] 表示子程序形状
D>不对称矩形] %% >] 表示不对称
E{菱形判断} %% {} 表示菱形
F{{六边形}} %% {{}} 表示六边形
G[/平行四边形/] %% [/ /] 表示平行四边形
H[\反向平行四边形\] %% [\ \] 表示反向
I[/梯形\\] %% [/\\] 表示梯形
A --> B %% --> 实线箭头
B -.-> C %% -.-> 虚线箭头
C ==> D %% ==> 粗线箭头
D -->|带文字| E %% |文字| 添加标签
E --> 无箭头 F %% --> 无箭头2. 时序图 (Sequence Diagram)
展示系统间或对象间的交互顺序:
mermaid
sequenceDiagram
participant U as 用户
participant C as 客户端
participant A as API网关
participant S as 服务端
participant D as 数据库
U->>C: 点击提交
C->>A: POST /api/order
A->>S: 转发请求
S->>D: 查询库存
D-->>S: 返回库存状态
alt 库存充足
S->>D: 创建订单
D-->>S: 订单创建成功
S-->>A: 返回成功
A-->>C: 200 OK
C-->>U: 显示成功页面
else 库存不足
S-->>A: 返回错误
A-->>C: 400 Bad Request
C-->>U: 显示库存不足
end语法详解:
mermaid
sequenceDiagram
%% 定义参与者
participant A as 参与者A
participant B as 参与者B
%% 消息类型
A->>B: 实线箭头(异步)
A-->>B: 虚线箭头(返回)
A->xB: 实线无箭头
A--xB: 虚线无箭头
A->>B: 实线实心箭头(同步)
A-->>B: 虚线实心箭头
%% 激活框
activate A
A->>B: 请求
activate B
B-->>A: 响应
deactivate B
deactivate A
%% 条件分支
alt 条件1
A->>B: 操作1
else 条件2
A->>B: 操作2
else 默认
A->>B: 默认操作
end
%% 循环
loop 每分钟
A->>B: 心跳检测
end
%% 并行
par 并行操作1
A->>B: 请求1
and 并行操作2
A->>C: 请求2
end3. 类图 (Class Diagram)
展示类的结构和关系:
mermaid
classDiagram
class User {
+String id
+String email
+String name
+Date createdAt
+login()
+logout()
}
class Order {
+String id
+String userId
+Number total
+String status
+placeOrder()
+cancelOrder()
}
class Product {
+String id
+String name
+Number price
+Number stock
}
class OrderItem {
+String orderId
+String productId
+Number quantity
+Number price
}
User "1" --> "*" Order : 拥有
Order "1" --> "*" OrderItem : 包含
OrderItem "*" --> "1" Product : 引用
note for User "用户实体类"
note for Order "订单实体类"关系类型:
mermaid
classDiagram
classA --|> classB : 继承 (Inheritance)
classC --* classD : 组合 (Composition)
classE --o classF : 聚合 (Aggregation)
classG --> classH : 关联 (Association)
classI .. classJ : 依赖 (Dependency)
classK ..|> classL : 实现 (Realization)
classM -- classN : 链接 (Link)4. 甘特图 (Gantt)
项目进度管理:
mermaid
gantt
title 项目开发计划
dateFormat YYYY-MM-DD
section 设计阶段
需求分析 :done, a1, 2024-01-01, 3d
UI设计 :active, a2, after a1, 5d
原型评审 :a3, after a2, 2d
section 开发阶段
后端API开发 :b1, after a3, 10d
前端页面开发 :b2, after a3, 12d
接口联调 :b3, after b1, 3d
section 测试阶段
单元测试 :c1, after b2, 5d
集成测试 :c2, after b3, 5d
Bug修复 :c3, after c2, 3d
section 发布阶段
部署上线 :d1, after c3, 2d
用户培训 :d2, after d1, 3d5. 状态图 (State Diagram)
展示状态转换:
mermaid
stateDiagram-v2
[*] --> 待付款
待付款 --> 已付款 : 支付成功
待付款 --> 已取消 : 超时/取消
已付款 --> 已发货 : 商家发货
已付款 --> 已退款 : 申请退款
已发货 --> 已收货 : 确认收货
已发货 --> 已退货 : 申请退货
已收货 --> [*]
已取消 --> [*]
已退款 --> [*]
已退货 --> [*]6. 实体关系图 (ER Diagram)
数据库设计:
mermaid
erDiagram
USER ||--o{ ORDER : places
USER {
string id PK
string email
string password
string name
datetime created_at
}
ORDER ||--|{ ORDER_ITEM : contains
ORDER {
string id PK
string user_id FK
decimal total_amount
string status
datetime created_at
}
ORDER_ITEM }|--|| PRODUCT : references
ORDER_ITEM {
string id PK
string order_id FK
string product_id FK
int quantity
decimal price
}
PRODUCT {
string id PK
string name
string description
decimal price
int stock
}在 React 中使用
基础组件
tsx
'use client'
import { useEffect, useRef } from 'react'
import mermaid from 'mermaid'
interface MermaidDiagramProps {
chart: string
className?: string
}
export function MermaidDiagram({ chart, className }: MermaidDiagramProps) {
const containerRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (!containerRef.current) return
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'strict',
})
mermaid.render('mermaid-svg', chart).then(({ svg }) => {
if (containerRef.current) {
containerRef.current.innerHTML = svg
}
})
}, [chart])
return <div ref={containerRef} className={className} />
}支持深色模式
tsx
'use client'
import { useEffect, useRef } from 'react'
import mermaid from 'mermaid'
import { useTheme } from 'next-themes'
interface MermaidDiagramProps {
chart: string
}
export function MermaidDiagram({ chart }: MermaidDiagramProps) {
const containerRef = useRef<HTMLDivElement>(null)
const { theme } = useTheme()
useEffect(() => {
if (!containerRef.current) return
const mermaidTheme = theme === 'dark' ? 'dark' : 'default'
mermaid.initialize({
startOnLoad: false,
theme: mermaidTheme,
themeVariables: {
// 自定义变量
primaryColor: '#e1f5fe',
primaryTextColor: '#01579b',
primaryBorderColor: '#0288d1',
lineColor: '#0288d1',
secondaryColor: '#fff3e0',
tertiaryColor: '#e8f5e9',
}
})
const id = `mermaid-${Math.random().toString(36).substr(2, 9)}`
mermaid.render(id, chart).then(({ svg }) => {
if (containerRef.current) {
containerRef.current.innerHTML = svg
}
})
}, [chart, theme])
return (
<div
ref={containerRef}
className="flex justify-center overflow-x-auto"
/>
)
}Markdown 中自动渲染
tsx
'use client'
import { useEffect } from 'react'
import mermaid from 'mermaid'
interface MarkdownContentProps {
content: string
}
export function MarkdownContent({ content }: MarkdownContentProps) {
useEffect(() => {
mermaid.initialize({
startOnLoad: true,
theme: 'default',
})
// 查找并渲染所有 mermaid 代码块
mermaid.run({
querySelector: '.language-mermaid',
})
}, [content])
return (
<div
className="prose"
dangerouslySetInnerHTML={{ __html: content }}
/>
)
}主题定制
内置主题
typescript
mermaid.initialize({
theme: 'default' // 默认浅色
// theme: 'dark' // 深色主题
// theme: 'forest' // 森林绿
// theme: 'neutral' // 中性灰
// theme: 'base' // 基础主题(可自定义)
})自定义主题
typescript
mermaid.initialize({
theme: 'base',
themeVariables: {
// 主要颜色
primaryColor: '#bbdefb',
primaryTextColor: '#1565c0',
primaryBorderColor: '#1976d2',
// 线条
lineColor: '#424242',
// 次要颜色
secondaryColor: '#ffe0b2',
secondaryTextColor: '#e65100',
secondaryBorderColor: '#f57c00',
// 第三颜色
tertiaryColor: '#c8e6c9',
tertiaryTextColor: '#2e7d32',
tertiaryBorderColor: '#388e3c',
// 背景
background: '#fafafa',
mainBkg: '#ffffff',
// 节点边框
nodeBorder: '#bdbdbd',
clusterBkg: '#f5f5f5',
clusterBorder: '#9e9e9e',
// 标题
titleColor: '#212121',
edgeLabelBackground: '#ffffff',
// 时序图特定
actorBorder: '#757575',
actorBkg: '#ffffff',
actorTextColor: '#212121',
actorLineColor: '#bdbdbd',
signalColor: '#424242',
signalTextColor: '#212121',
}
})CSS 样式覆盖
css
/* 自定义 Mermaid 样式 */
.mermaid {
font-family: 'Inter', sans-serif;
}
/* 节点样式 */
.mermaid .node rect {
fill: #e3f2fd;
stroke: #1976d2;
stroke-width: 2px;
rx: 8;
ry: 8;
}
/* 文字样式 */
.mermaid .node .label {
color: #1565c0;
font-size: 14px;
font-weight: 500;
}
/* 连线样式 */
.mermaid .edgePath .path {
stroke: #424242;
stroke-width: 2px;
}
/* 箭头样式 */
.mermaid .arrowheadPath {
fill: #424242;
}Cloudflare Workers 中的 SSR Stubs
问题
Mermaid 依赖浏览器 DOM API,在服务端渲染时会报错:
Error: document is not defined
解决方案
typescript
// vite.config.ts
const ssrOnlyStubs = () => ({
name: 'ssr-only-stubs',
enforce: 'pre',
resolveId(id, importer, { ssr }) {
if (!ssr) return null
// Mermaid 及其依赖
if (id.includes('mermaid') ||
id.includes('beautiful-mermaid') ||
id.includes('@streamdown/')) {
return '\0stub:mermaid'
}
},
load(id) {
if (id === '\0stub:mermaid') {
return `
export default {
initialize: () => {},
render: () => Promise.resolve({ svg: '' }),
run: () => Promise.resolve(),
parse: () => ({}),
}
`
}
}
})客户端动态加载
tsx
'use client'
import { useEffect, useRef, useState } from 'react'
interface MermaidDiagramProps {
chart: string
}
export function MermaidDiagram({ chart }: MermaidDiagramProps) {
const containerRef = useRef<HTMLDivElement>(null)
const [svg, setSvg] = useState('')
useEffect(() => {
// 仅在客户端加载 Mermaid
import('mermaid').then((mermaid) => {
mermaid.default.initialize({
startOnLoad: false,
theme: 'default',
})
const id = `mermaid-${Date.now()}`
mermaid.default.render(id, chart).then(({ svg }) => {
setSvg(svg)
})
})
}, [chart])
return (
<div
ref={containerRef}
className="flex justify-center"
dangerouslySetInnerHTML={{ __html: svg }}
/>
)
}最佳实践
1. 图表命名规范
mermaid
%% 使用有意义的节点 ID
graph TD
%% 好的命名
UserLogin[用户登录] --> ValidateToken{验证Token}
ValidateToken -->|有效| Dashboard[显示仪表盘]
ValidateToken -->|无效| LoginPage[返回登录页]
%% 避免无意义的命名
%% A --> B --> C2. 复杂图表拆分
mermaid
%% 主流程图
graph TD
subgraph 用户认证
A[登录] --> B[验证]
end
subgraph 订单处理
C[创建订单] --> D[支付]
D --> E[发货]
end
B --> C3. 添加注释
mermaid
graph TD
%% 这是用户登录流程
A[用户输入] --> B{验证}
%% 验证成功分支
B -->|成功| C[进入系统]
%% 验证失败分支
B -->|失败| D[显示错误]4. 性能优化
typescript
// 缓存渲染结果
const cache = new Map<string, string>()
export async function renderMermaid(chart: string): Promise<string> {
if (cache.has(chart)) {
return cache.get(chart)!
}
const { svg } = await mermaid.render('id', chart)
cache.set(chart, svg)
return svg
}相关文章
- VibeAny 部署到 Cloudflare Workers 完全指南 - 了解完整的部署流程
- SSR Stubs 技术详解 - 深入了解 SSR stubs 优化原理
- Shiki 代码高亮完全指南 - 代码高亮的配置和使用
分享: