状态图

“状态图(Statechart Diagram)是描述一个实体基于事件反应的动态行为,显示了该实体如何根据当前所处的状态对不同的事件做出反应。通常我们创建一个UML状态图是为了以下的研究目的:研究类、角色、子系统、或组件的复杂行为。”          – 百度百科

Mermaid可以渲染状态图。Mermaid的语法试图与plantUml中使用的语法保持一致,这样有助于用户在mermaidplantUml之间共享图表。

CSDN mermaid v8.14.0 不支持标题 title,以下是 mermaid v10.2.3 的代码

代码:

```mermaid

title: 简单示例

stateDiagram-v2
[*] --> 静止
静止 --> [*]
静止 --> 移动
移动 --> 静止
移动 --> 碰撞
碰撞 --> [*]
```

---
title: 简单示例
---
stateDiagram-v2
    [*] --> 静止
    静止 --> [*]

    静止 --> 移动
    移动 --> 静止
    移动 --> 碰撞
    碰撞 --> [*]

旧版本渲染效果:

代码:

```mermaid
stateDiagram
[*] --> 静止
静止 --> [*]
静止 --> 移动
移动 --> 静止
移动 --> 碰撞
碰撞 --> [*]
```

静止
移动
碰撞

在状态图中,系统通过状态和状态之间的转换来描述。上面的示例图表展示了三个状态:静止移动碰撞。你开始于静止状态。从静止可以转换到移动 状态。从 移动 可以转换回 静止 状态或转换至 碰撞 状态。从 静止 无法直接转换到 碰撞。(如果你还静止着,那就不可能碰撞。)


状态

一个状态可以有多种声明方式。最简单的方式是仅用序号定义一个状态:

代码:

```mermaid
stateDiagram-v2
状态序号
```

状态序号

另一种方法是使用 state 关键字和描述,如下所示:

代码:

```mermaid
stateDiagram-v2
state “这是状态1的描述” as 状态1
```

这是状态1的描述

另一种定义带描述的状态的方法是先定义状态的序号,接着加上冒号和该状态的描述,如下所示:

代码:

```mermaid
stateDiagram-v2
状态1 : 这是状态1的描述
```

这是状态1的描述

状态转换

转换是指一个状态通过路径/边缘转换到另一个状态的过程,这通常使用文本箭头“-->”来表示。

当你在两个状态之间定义一个转换时,如果这些状态还没有被定义,那么这些未定义的状态会使用转换中的序号进行定义。之后,你可以为这些使用转换ID定义的状态添加描述信息。

代码:

```mermaid
stateDiagram-v2
状态1 --> 状态2
```

状态1
状态2

可以向转换添加文本来描述其代表的内容:

代码:

```mermaid
stateDiagram-v2
状态1 --> 状态2: 转换
```

转换
状态1
状态2

开始和结束

有两个特殊状态表示图表的起始和终止。它们使用的语法是 [*],转换的方向定义了它是起始状态还是终止状态。

代码:

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

状态1

复合状态

在实际的状态图使用中,一个状态可能包含多个内部状态,从而产生了维度较高的状态图,这些状态被称为复合状态。

为定义一个复合状态,你需要使用 state 关键字,接着是复合状态的序号,并将复合状态的内容放在大括号 {} 中。以下是一个示例:

代码:

```mermaid
stateDiagram-v2
[*] --> 复合状态1
state 复合状态1 {
[*] --> 状态2
状态2 --> [*]
}
```

复合状态1
状态2

你可以使用多层嵌套来定义复合状态:

代码:

```mermaid
stateDiagram-v2
[*] --> 复合状态1
state 复合状态1 {
[*] --> 复合状态2
state 复合状态2 {
[*] --> 状态2
状态2 --> 复合状态3
state 复合状态3 {
[*] --> 状态3
状态3 --> [*]
}
}
}
```

复合状态1
复合状态2
状态2
复合状态3
状态3

你也可以在复合状态之间定义转换:

代码:

```mermaid
stateDiagram-v2
[*] --> 复合状态1
复合状态1 --> 复合状态2
复合状态1 --> 复合状态3
state 复合状态1 {
[*] --> 状态1
状态1 --> [*]
}
state 复合状态2 {
[*] --> 状态2
状态2 --> [*]
}
state 复合状态3 {
[*] --> 状态3
状态3 --> [*]
}
```

复合状态1
状态1
复合状态2
状态2
复合状态3
状态3

你不能在属于不同复合状态的内部状态之间定义转换。


选择

有时候你需要模拟在几条路径之间做出选择,可以使用 <<choice>> 实现。

代码:

```mermaid
stateDiagram-v2
state 状态选择 <<choice>>
[*] --> 正数
正数 --> 状态选择
状态选择 --> 假: 如果 n < 0
状态选择 --> 真 : 如果 n >= 0
```

如果 n < 0
如果 n >= 0
正数

分支合并

可以使用 <<fork>> <<join>> 在状态机中指定一个分支和合并。

代码:

```mermaid
stateDiagram-v2
state 分支 <<fork>>
[*] --> 分支
分支 --> 状态1
分支 --> 状态2
state 合并 <<join>>
状态1 --> 合并
状态2 --> 合并
合并 --> 状态3
状态3 --> [*]
```

状态1
状态2
状态3

备注

有时候,添加一个备注比任何语言都更能清晰地表达信息。在状态图中同样如此。

在状态图中,你可以选择将备注放置在节点的右侧或左侧。

代码:

```mermaid
stateDiagram-v2
direction LR
状态1: 这是状态1
note right of 状态1
重要信息!你可以写一些备注
end note
状态1 --> 状态2
note left of 状态2 : 这是在状态2左侧的备注.
```

这是状态1
重要信息!你可以写一些备注
状态2
这是在状态2左侧的备注.

并发

plantUml 中,你可以使用 -- 符号来指定并发行为。

代码:

```mermaid
stateDiagram-v2
[*] --> 激活
state 激活 {
[*] --> 数字锁定关闭
数字锁定关闭 --> 数字锁定开启 : 数字锁定键按下事件
数字锁定开启 --> 数字锁定关闭 : 数字锁定键按下事件

[*] --> 大写锁定关闭
大写锁定关闭 --> 大写锁定开启 : 大写锁定键按下事件
大写锁定开启 --> 大写锁定关闭 : 大写锁定键按下事件

[*] --> 滚动锁定关闭
滚动锁定关闭 --> 滚动锁定开启 : 滚动锁定键按下事件
滚动锁定开启 --> 滚动锁定关闭 : 滚动锁定键按下事件
}
```

激活
数字锁定键按下事件
数字锁定键按下事件
数字锁定关闭
数字锁定开启
大写锁定键按下事件
大写锁定键按下事件
大写锁定关闭
大写锁定开启
滚动锁定键按下事件
滚动锁定键按下事件
滚动锁定关闭
滚动锁定开启

设置状态图的方向

可以设置以下几种方向:

  • LR 从左到右
  • RL 从右到左
  • TB 从上到下
  • BT 从下到上

在状态图中,你可以使用 direction来设置状态图的排列方向,如下面的例子所示。

代码:

```mermaid
stateDiagram
direction LR
[*] --> 壹
壹 --> 贰
贰 --> 叁
state 贰 {
direction LR
一 --> 二
}
贰 --> 肆
```

注释

在状态图中,可以添加注释来说明状态和转换之间的信息,这些注释对解析器来说是无效的。注释必须放在它们自己的一行上,并以 %% (双百分号) 开头。任何在注释开始后到下一个新行之间的文本都将被视为注释,包括任何图表语法。

代码:

```mermaid
stateDiagram-v2
[*] --> 静止
静止 --> [*]
%% 这是一行注释
静止 --> 移动
移动 --> 静止 %% 这是行尾注释
移动 --> 碰撞
碰撞 --> [*]
```

静止
移动
碰撞

classDefs 设置样式

与其他图表(如流程图)一样,在状态图中也可以定义样式,并将该命名样式应用于状态或状态集。

以下是目前使用状态图 classDefs 的限制:

  1. 不能应用于起始状态或结束状态。
  2. 不能应用于或在复合状态中使用。
    这些功能正在开发中,将在未来版本中提供。

您可以使用 classDef 关键字定义样式,它是“class definition”的简称,其中 class 表示类似于 CSS 类的内容。接着是样式名称,然后是一个或多个属性-值对。每个属性-值对是有效的 CSS 属性名称,后面跟着一个冒号(:),然后是一个值。

下面是一个只有一个属性-值对classDef 示例。

classDef YiDongYangShi font-style:italic;

其中:

  • movement是样式名称
  • font-style是唯一的属性,
  • italicfont-style属性的值。

如果您想使用多个属性-值对,则可以在每个属性-值对之间添加逗号(,)。

这里有一个包含五个属性-值对的示例:

classDef PengZhuangYangShi fill:#f00,color:white,font-weight:bold,stroke-width:2px,stroke:yellow

其中:

  • badBadEvent是样式名称
  • 第一个属性-值对的属性是fill,其值是#f00
  • 第二个属性-值对的属性是color,其值是white
  • 第三个属性-值对的属性是font-weight,其值是bold
  • 第四个属性-值对的属性是stroke-width,其值是2px
  • 第五个属性-值对的属性是stroke,其值是yello

状态使用 classDef 样式

将 classDef 样式应用于状态有两种方法。

  1. 使用“class”关键字在单个语句中将 classDef 样式应用于一个或多个状态
  2. 使用“:::”运算符在转换语句中将 classDef 样式应用于状态,例如通过箭头与另一个状态相连。
1. class 语句

class 语句告知 Mermaid 将指定的 classDef 应用于一个或多个元素。格式为:

class [一个或多个状态名, 使用逗号分开] [使用classDef定义的样式名]

以下是一个示例,将 PengZhuangYangShi(碰撞样式) 样式应用于名为 PengZhuang(碰撞) 的状态:

class PengZhuang PengZhuangYangShi

以下是一个示例,将 YiDongYangShi(移动样式) 样式应用于名为YiDong(移动) 和 PengZhuang(碰撞) 两个状态:
class YiDong, PengZhuang YiDongYangShi

以下是一个图表,展示了这些示例的使用情况。请注意,Crash 状态应用了两种 classDef 样式:YiDongYangShiPengZhuangYangShi

注意 classDefclass 语句不支持Unicode字符(汉字等)。
CSDN mermaid v8.14.0 不支持样式设置 classDef class ,以下是 mermaid v10.2.3 的代码

代码:

```mermaid
stateDiagram
direction TB
accTitle: This is the accessible title
accDescr: This is an accessible description
classDef JingZhiYangShi fill:white
classDef YiDongYangShi font-style:italic
classDef PengZhuangYangShi fill:#f00,color:white,font-weight:bold,stroke-width:2px,stroke:yellow
[*]–> JingZhi
JingZhi --> [*]
JingZhi --> YiDong
YiDong --> JingZhi
YiDong --> PengZhuang
PengZhuang --> [*]
class JingZhi JingZhiYangShi
class YiDong, PengZhuang YiDongYangShi
class PengZhuang PengZhuangYangShi
class end PengZhuangYangShi
```

stateDiagram
   direction TB

   accTitle: This is the accessible title
   accDescr: This is an accessible description

   classDef JingZhiYangShi fill:white
   classDef YiDongYangShi font-style:italic
   classDef PengZhuangYangShi fill:#f00,color:white,font-weight:bold,stroke-width:2px,stroke:yellow

   [*]--> JingZhi
   JingZhi --> [*]
   JingZhi --> YiDong
   YiDong --> JingZhi
   YiDong --> PengZhuang
   PengZhuang --> [*]

   class JingZhi JingZhiYangShi
   class YiDong, PengZhuang YiDongYangShi
   class PengZhuang PengZhuangYangShi
   class end PengZhuangYangShi
2. 使用 ::: 运算符将样式应用于状态。

您可以使用 :::(三个冒号)运算符将 classDef 样式应用于状态。其语法为:

您可以在使用类语句的状态图中使用这个特性,包括开始和结束状态。例如:
CSDN mermaid v8.14.0 不支持样式设置 classDef ::: ,以下是 mermaid v10.2.3 的代码

代码:

```mermaid
stateDiagram
direction TB
accTitle: This is the accessible title
accDescr: This is an accessible description
classDef JingZhiYangShi fill:white
classDef YiDongYangShi font-style:italic;
classDef PengZhuangYangShi fill:#f00,color:white,font-weight:bold,stroke-width:2px,stroke:yellow
[*] --> 静止:::JingZhiYangShi
静止 --> [*]
静止 --> 移动:::YiDongYangShi
移动 --> 静止
移动 --> 碰撞:::YiDongYangShi
碰撞:::PengZhuangYangShi --> [*]
```

stateDiagram
   direction TB

   accTitle: This is the accessible title
   accDescr: This is an accessible description

   classDef JingZhiYangShi fill:white
   classDef YiDongYangShi font-style:italic;
   classDef PengZhuangYangShi fill:#f00,color:white,font-weight:bold,stroke-width:2px,stroke:yellow

   [*] --> 静止:::JingZhiYangShi
   静止 --> [*]
   静止 --> 移动:::YiDongYangShi
   移动 --> 静止
   移动 --> 碰撞:::YiDongYangShi
   碰撞:::PengZhuangYangShi --> [*]

状态名中使用空格

您可以通过先定义状态的序号,然后在后面引用该序号来添加空格到状态中。

在下面的示例中,有一个序号状态2并将其描述为带 空格 状态 2的状态。定义好之后,状态2在图表中用于第一个转换([*] --> 状态2),并且还用于将其与另一个状态 状态3 连接的转换 (状态2 --> 状态3)。
(状态2已经被设置成名为KongGeZhuanTaiYangShi(空格状态样式)的样式,以便与其他状态进行区分。)

CSDN mermaid v8.14.0 支持状态名带空格,但是不支持样式设置 classDef ::: ,以下是 mermaid v10.2.3 的代码

代码:

```mermaid
stateDiagram
classDef KongGeZhuanTaiYangShi font-style:italic,font-weight:bold,fill:white
状态2: 带 空格 状态 2
[*] --> 状态2:::KongGeZhuanTaiYangShi
[*] --> 状态1
状态1 --> 状态3
状态2 --> 状态3
状态3 --> [*]
```

stateDiagram
    classDef KongGeZhuanTaiYangShi font-style:italic,font-weight:bold,fill:white

    状态2: 带 空格 状态 2
    [*] --> 状态2
    [*] --> 状态1
    状态1 --> 状态3
    状态2 --> 状态3
    状态3 --> [*]
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐