Mermaid 状态图 #

状态图(State Diagram)用于展示对象在其生命周期内的状态转换过程,以及触发这些转换的事件。

基本语法 #

1. 基本结构 #

mermaid
stateDiagram-v2
  [*] --> 状态1
  状态1 --> 状态2
  状态2 --> [*]

2. 初始状态和终止状态 #

使用[*]表示初始状态和终止状态:

mermaid
stateDiagram-v2
  [*] --> 初始状态
  初始状态 --> 运行状态
  运行状态 --> 暂停状态
  暂停状态 --> 运行状态
  运行状态 --> [*]
  暂停状态 --> [*]

状态转换 #

1. 简单转换 #

mermaid
stateDiagram-v2
  [*] --> 关闭
  关闭 --> 打开: 按电源按钮
  打开 --> 关闭: 按电源按钮

2. 带条件的转换 #

可以在转换上添加条件:

mermaid
stateDiagram-v2
  [*] --> 准备
  准备 --> 运行: 开始
  运行 --> 成功: 条件1满足
  运行 --> 失败: 条件2满足
  成功 --> [*]
  失败 --> [*]

3. 事件和条件 #

可以在转换中同时指定事件和条件:

mermaid
stateDiagram-v2
  [*] --> 就绪
  就绪 --> 运行: 启动事件[条件]
  运行 --> 暂停: 暂停事件
  暂停 --> 运行: 继续事件
  运行 --> 完成: 完成事件
  暂停 --> 取消: 取消事件
  完成 --> [*]
  取消 --> [*]

复合状态 #

复合状态是包含其他状态的状态:

1. 简单复合状态 #

mermaid
stateDiagram-v2
  [*] --> 未登录
  未登录 --> 登录中: 输入凭证
  登录中 --> 已登录: 验证成功
  登录中 --> 未登录: 验证失败
  
  state 已登录 {
    [*] --> 首页
    首页 --> 个人中心
    个人中心 --> 设置
    设置 --> 首页
  }
  
  已登录 --> 未登录: 退出登录

2. 正交状态 #

正交状态表示同时进行的多个状态机:

mermaid
stateDiagram-v2
  [*] --> 运行
  
  state 运行 {
    [*] --> 状态1
    状态1 --> 状态2
    
    --
    
    [*] --> 状态A
    状态A --> 状态B
  }
  
  运行 --> [*]

选择和连接 #

1. 选择(Choice) #

选择表示根据条件选择不同的转换路径:

mermaid
stateDiagram-v2
  [*] --> 开始
  开始 --> 选择点: 处理
  
  state 选择点 <<choice>>
  选择点 --> 路径1: 条件1
  选择点 --> 路径2: 条件2
  选择点 --> 路径3: 条件3
  
  路径1 --> 结束
  路径2 --> 结束
  路径3 --> 结束
  结束 --> [*]

2. 连接(Junction) #

连接用于合并或分支转换路径:

mermaid
stateDiagram-v2
  [*] --> 状态1
  [*] --> 状态2
  
  state 连接点 <<fork>>
  状态1 --> 连接点
  状态2 --> 连接点
  连接点 --> 状态3
  连接点 --> 状态4
  
  state 合并点 <<join>>
  状态3 --> 合并点
  状态4 --> 合并点
  合并点 --> [*]

历史状态 #

历史状态用于记住复合状态上次离开时的子状态:

1. 浅历史(Shallow History) #

只记住直接子状态:

mermaid
stateDiagram-v2
  [*] --> 复合状态
  
  state 复合状态 {
    [*] --> 子状态1
    子状态1 --> 子状态2
    子状态2 --> 子状态3
    
    state 历史 <<history>>
  }
  
  复合状态 --> 外部状态: 退出
  外部状态 --> 复合状态: 重新进入
  外部状态 --> 复合状态: 从历史继续
  复合状态: 从历史继续 --> 历史

2. 深历史(Deep History) #

记住所有层级的子状态:

mermaid
stateDiagram-v2
  [*] --> 复合状态
  
  state 复合状态 {
    [*] --> 子状态1
    子状态1 --> 子状态2
    
    state 子状态2 {
      [*] --> 孙状态1
      孙状态1 --> 孙状态2
    }
    
    state 历史 <<history>>
  }
  
  复合状态 --> 外部状态: 退出
  外部状态 --> 历史: 从深历史继续

活动和动作 #

1. 进入和退出动作 #

可以在状态的进入和退出时执行动作:

mermaid
stateDiagram-v2
  [*] --> 状态1: 初始转换
  
  state 状态1 {
    [*] --> 子状态1
    entry / 进入状态1
    exit / 退出状态1
    
    子状态1 --> 子状态2: 转换1
    子状态2 --> 子状态1: 转换2
  }
  
  状态1 --> 状态2: 转换3
  
  state 状态2 {
    entry / 进入状态2
    exit / 退出状态2
  }
  
  状态2 --> [*]: 结束

2. 内部转换 #

内部转换不改变状态,但可以执行动作:

mermaid
stateDiagram-v2
  [*] --> 运行
  
  state 运行 {
    entry / 开始运行
    exit / 停止运行
    [*] --> 子状态
    
    子状态: 事件 / 执行动作
  }
  
  运行 --> [*]

高级功能 #

1. 注释 #

可以添加注释:

mermaid
stateDiagram-v2
  [*] --> 状态1
  状态1 --> 状态2
  %% 这是一个注释
  状态2 --> [*]

2. 状态样式 #

可以为状态添加自定义样式:

mermaid
stateDiagram-v2
  [*] --> 就绪
  就绪 --> 运行
  运行 --> 完成
  完成 --> [*]
  
  stateDef 强调 fill:#f96,stroke:#333,stroke-width:2px;
  运行 : 强调

3. 并行区域 #

并行区域使用--分隔:

mermaid
stateDiagram-v2
  [*] --> 工作
  
  state 工作 {
    [*] --> 处理数据
    处理数据 --> 分析结果
    
    --
    
    [*] --> 检查系统
    检查系统 --> 生成报告
  }
  
  工作 --> [*]

最佳实践 #

  1. 清晰的状态命名:使用有意义的状态名称
  2. 明确的转换条件:在转换上添加清晰的事件和条件
  3. 适当使用复合状态:将相关状态组织为复合状态
  4. 合理使用历史状态:需要记住之前状态时使用历史状态
  5. 避免过度复杂:将复杂的状态图分解为多个子图

常见问题 #

问题:初始状态不显示 #

解决方案:确保使用[*]定义初始状态

问题:复合状态内部转换不正确 #

解决方案:确保复合状态内部有自己的初始状态[*]

问题:条件转换不生效 #

解决方案:确保条件格式正确,使用[条件]语法

完整示例 #

下面是一个完整的订单状态图示例:

mermaid
stateDiagram-v2
  [*] --> 待付款
  
  待付款 --> 已付款: 用户支付
  待付款 --> 已取消: 用户取消
  待付款 --> 已关闭: 超时未支付
  
  已付款 --> 待发货: 系统确认
  已付款 --> 退款中: 用户申请退款
  
  state 待发货 {
    [*] --> 配货中
    配货中 --> 已出库: 仓库发货
    已出库 --> 待收货
  }
  
  待发货 --> 部分发货: 部分商品缺货
  待发货 --> 已取消: 商家取消
  
  待收货 --> 已完成: 用户确认收货
  待收货 --> 退款中: 用户申请退货
  
  退款中 --> 已退款: 退款成功
  退款中 --> 退款失败: 退款审核不通过
  
  已完成 --> [*]
  已取消 --> [*]
  已关闭 --> [*]
  已退款 --> [*]
  退款失败 --> 待收货: 继续交易
最后更新:2026-02-08