共计 7931 个字符,预计需要花费 20 分钟才能阅读完成。
Typora
反对应用 mermaid
进行绘图,其中就包含流程图。
日常生活中利用流程图的场景并不算太多,在写代码的过程中也更偏差应用伪代码。近期读《计算机程序设计艺术》卷一,上来就是一张流程图,不知怎的,忽然感觉流程图不可或缺。或者流程图搭配伪代码更好。
以上是我强行扯出的写本文的理由。
对于 mermaid
mermaid
泛滥代码绘图工具之一。最先接触的是 PlantUML
,过后为了画类图交软件文档,但又不想手动画,于是搜寻到了这个工具。PlantUML
如其名,次要是 UML
图,反对的图较少,且依赖较多,配置的步骤较多。
mermaid
尽管没有 PlantUML
那样残缺反对 UML
,但根本的图形都能绘制,且感激大前端的倒退,其只是一个“简略”的 .js
文件,导入浏览器导出应用,在 Markdown
这种兼容 HTML
的标记语言下,真心流程。
它反对简略的程序流程图,之所以说简略,是因为残缺的流程切实太过于简单。如果用不上,简单的就搁置吧,mermaid
曾经足够应用了。
装置 mermaid
参考 装置教程。
接触 mermaid
次要是 Typora
自身反对应用 mermaid
,我的计划是在 Typora
实现编辑,随后导出 HTML
,再到某个反对 Markdown
的平台进行公布。局部网站本身反对 mermaid
。
绘制到简略流程图如下:
graph LR
A([开始]) --> B[/ 编辑文章 /]
B --> C{内容实现?}
C -->| 是 | D{再编辑?}
C -->| 否 | B
D -->| 否 | Save[保留]
Save --> E{导出?}
D -->| 是 | B
E -->| 否 | End([完结])
E -->| 是 | ExportHTML[/ 导出 HTML/]
ExportHTML --> Publish[公布]
Publish --> End
Markdown 中应用 mermaid
在 Typora
应用 mermaid
很简略,间接引入代码即可:
```mermaid
```
而咱们须要应用流程图,能够参考文档,引入流程图间接应用 flowchart
或者 graph
关键字,同时须要明确指定流程图的绘制方向,TD
或者 TB
示意从上到下绘制,LR
示意从左到右绘制。(就是上下左右首字母示意)。而 flowchart
和 graph
可能应用的款式不一样,flowchart
绝对箭头比拟平滑,能用的箭头款式多样,graph
的款式绝对古板。咱们能够尝试一个简略的流程:
```mermaid
graph LR
START([开始])
END([完结])
START --> A[测试]
A --> isRight{正确?}
isRight -->| 是 | END
isRight -->| 否 | A
```
上述代码绘制如图:
graph LR
START([开始])
END([完结])
START --> A[测试]
A --> isRight{正确?}
isRight -->| 是 | END
isRight -->| 否 | A
咱们将 graph
替换成 flowchart
如图:
flowchart LR
START([开始])
END([完结])
START --> A[测试]
A --> isRight{正确?}
isRight -->| 是 | END
isRight -->| 否 | A
目前开来仅仅是款式存在区别,而文档中标注 flowchart
属于 Beta
状态,文档中只列举出了更多的箭头反对和子流程图反对。这并非咱们应该关注的重点,因此应用那个关键字,齐全在于集体爱好。flowchart
虽在文字上具备较为强烈的识别性,但 graph
绘制出了图像更清晰,在 Typora
中也有代码高亮,且 flowchat
提供的性能也用不上,因而后续应用 graph
作为关键字。
流程图根底
流程图的次要功能在于绝对文字能更直观形容某件事情的过程。
而应用代码实现流程图的构建,更像是伪代码去即时展示逻辑,当然也不便不相熟代码的人间接了解代码的基本思路(不晓得这有啥用)。绘制流程图,理清本人的逻辑是最次要的。
而人与人交换都须要一个标准,流程图自身有一个标准。
流程图符号
此处将列举惯例符号和 mermaid
对应的代码。
mermaid
并没有规定那个符号表明哪个意思,只是表述了该符号的形态。
1. 流程
示意执行或者解决某些工作。
在 mermaid
中流程的符号很简略,就是中括号 []
,示例如下:
graph LR
A[流程 1]
B[流程 2]
A --> B
其成果如下:
graph LR
A[流程 1]
B[流程 2]
A --> B
mermaid
中,流程是一个根本的 node
,它的形态是矩形,还有圆角矩形(应用 ()
表述),两者区别不大,没有特定的要求,但 []
更容易输出,因此应用 ()
的必要不大。
2. 开始或完结
在 文档 中,所有开始或结符号都是应用流程间接代替的,并没有给出具体的要求。但流程图标准当中,开始和完结该当有别与流程的形态。在 mermaid
中应用 ([])
能够绘制一个区别于流程的图形,如下:
graph LR
START([开始])
END([完结])
START --> END
后果如下:
graph LR
START([开始])
END([完结])
START --> END
文档 中,称之为 A stadium-shaped node
,其形态相似于体育场。而开始和完结只有一个,在初始时将其定义好,后续能够间接应用。
特地留神,定义完结的时候,切勿应用小写 end
,否则可能倒置流程图绘制中断
3. 断定
断定是对立的,mermaid
应用 {}
示意。如下:
graph LR
START([开始])
END([完结])
Flow[流程]
isTrue{正确?}
isTrue -->| 是 | END
isTrue -->| 否 | Flow
START --> Flow --> isTrue
成果如下:
graph LR
START([开始])
END([完结])
Flow[流程]
isTrue{正确?}
isTrue -->| 是 | END
isTrue -->| 否 | Flow
START --> Flow --> isTrue
如代码所示,咱们定义 isTrue
作为一个断定框,其内容是“正确?”,而正确与否的之后的流程如何解决很简略,间接在下一个前流程应用 | 是 / 否 |
即可。
4. 子流程
如其名,是一部分流程的汇合,次要功能在于简化整个流程图。而其外部的流程能够以附件形式展现到另一个流程图中。相似于子程序,mermaid
中为 A node in a subroutine shape。
代码如下:
graph LR
id[[子流程]]
成果如下:
graph LR
id[[子流程]]
即应用两个中括号示意,[[]]
。
5. 数据库
示意存储地位,属于扩大。
代码如下:
graph LR
DB[(数据库)]
成果如下:
graph LR
DB[(数据库)]
符号是 [()]
。
6. 页面内援用
即接口,示意两个流程图间的接口。
用处在于:
- 连贯到下一页;
- 防止流线穿插;
- 防止流线太长;
代码如下:
graph LR
OUT((接口))
成果如下:
graph LR
OUT((接口))
符号是 (())
。
7. 输出 / 输入
呈现输出或者输入的时候,应该区别于流程。
代码如下:
graph LR
input[/ 输出 /]
成果如下:
graph LR
input[/ 输出 /]
在 mermaid
还有反向的平行四边形,其符号与上述相同,[\\]
,成果如:
graph LR
input[\ 输出 \]
但咱们个别应用第一个。
8.(附加)箭头款式
流程图仿佛只有实线箭头,其余箭头很少见到,但 mermaid
提供了不少款式的箭头。
代码如下:
graph LR
A --- | 直线 | B
A ----- | 直线长度是 - 符号定义 - 长度 3 -5| B0
A --> | 直线箭头 | B1
A ---> | 长直线箭头 | B2
A === | 粗线 | B3
A ==> | 粗线箭头 | B4
A -.- | 虚线 | B5
A -.-> | 虚线箭头 | B6
成果如下:
graph LR
A --- | 直线 | B
A ----- | 直线长度是 - 符号定义 - 长度 3 -5| B0
A --> | 直线箭头 | B1
A ---> | 长直线箭头 | B2
A === | 粗线 | B3
A ==> | 粗线箭头 | B4
A -.- | 虚线 | B5
A -.-> | 虚线箭头 | B6
能够依据本人的需要应用。
当然,mermaid
还提供许多其余图形,包含梯形等等。这些请参考文档。
接下来咱们绘制下流程图的根底构造。
流程图的根本构造
流程图有三大根本构造,别离是:程序构造、抉择构造和循环构造,程序的形成也根本如此。在流程图绘制标准中,有规定这些构造的绘制办法,而利用 mermaid
绘制进去的图形仿佛并不那么标准。
1. 程序构造
程序构造即按程序先后顺序执行,从上往下 / 从左往右,一个一个执行。最根本的构造。
代码如下:
graph LR
START([开始])
END([完结])
START --> A
A --> B
B --> C
C --> END
成果如下:
graph LR
START([开始])
END([完结])
START --> A
A --> B
B --> C
C --> END
2. 抉择构造
抉择,即分支,即 if-else
构造:
graph TD
isTrueA{条件 A}
isTrueB{条件 B}
isTrueC{条件 C}
A([开始]) --> isTrueA
isTrueA --> | 是 | A1[步骤 1]
isTrueA --> | 否 | A2[步骤 2]
A1 --> AE([完结])
A2 --> AE
B([开始]) --> isTrueB
isTrueB --> | 是 | BE([完结])
isTrueB --> | 否 | B1[步骤 3]
B1 --> BE
C([开始]) --> isTrueC
isTrueC --> | 是 | C1[步骤 4]
isTrueC --> | 否 | CE([完结])
C1 --> CE
成果如下:
graph TD
isTrueA{条件 A}
isTrueB{条件 B}
isTrueC{条件 C}
A([开始]) --> isTrueA
isTrueA --> | 是 | A1[步骤 1]
isTrueA --> | 否 | A2[步骤 2]
A1 --> AE([完结])
A2 --> AE
B([开始]) --> isTrueB
isTrueB --> | 是 | BE([完结])
isTrueB --> | 否 | B1[步骤 3]
B1 --> BE
C([开始]) --> isTrueC
isTrueC --> | 是 | C1[步骤 4]
isTrueC --> | 否 | CE([完结])
C1 --> CE
能够看到,尽管咱们依照程序编写代码,但 条件 B
和 条件 C
的绘制中能够看出有步骤的状况在右,若两边都蕴含步骤,则按程序绘制。因为“是否”是依照 | 文字 |
嵌入的,则依照程序缺省行为执行绘制。
3. 循环构造
顾名思义,在肯定的条件下,其会实现反复动作。
循环构造又有当型和直到型,能够看作 while
和 do while(! 条件)
。
代码:
graph TD
isTrue1{当型判断?}
isTrue2{直到型判断?}
A([开始]) --> isTrue1
isTrue1 --> | 是 | A1[步骤 1] --> isTrue1
isTrue1 --> | 否 | AE([完结])
B([开始]) --> B1[步骤 2]
B1 --> isTrue2
isTrue2 --> | 是 | BE([完结])
isTrue2 --> | 否 | B1
成果:
graph TD
isTrue1{当型判断?}
isTrue2{直到型判断?}
A([开始]) --> isTrue1
isTrue1 --> | 是 | A1[步骤 1] --> isTrue1
isTrue1 --> | 否 | AE([完结])
B([开始]) --> B1[步骤 2]
B1 --> isTrue2
isTrue2 --> | 是 | BE([完结])
isTrue2 --> | 否 | B1
都到这了,不思考什么画图标准了……
案例
来几个经典的案例。
1. 猜数字
猜数字 number
,为随机数。
- 输出数字 n
- 判断大小,提醒大或者小
- 猜对提醒,是否持续
- 不持续退出,持续则从新生成
number
,反复步骤 1 -4
graph TD
START([开始])
END([完结])
%% 该数字非输出,由系统生成
gen_number[生成随机数字 number-- 系统生成]
input_n[/ 输出数字 n /]
%% 定义判断条件
n_eq_number?{n == number?}
n_lt_number?{n < number?}
continue?{持续?}
%% 提醒
ALERT_gt[/ 提醒数字大了 /]
ALERT_eq[/ 提醒数字正确 /]
ALERT_lt[/ 提醒数字小了 /]
START --> gen_number --> input_n
input_n --> n_eq_number?
n_eq_number? --> | 是 | ALERT_eq --> continue?
n_eq_number? --> | 否 | n_lt_number?
n_lt_number? --> | 是 | ALERT_lt
n_lt_number? --> | 否 | ALERT_gt
n_lt_number? --> input_n
continue? --> | 是 | gen_number
continue? --> | 否 | END
graph TD
START([开始])
END([完结])
%% 该数字非输出,由系统生成
gen_number[生成随机数字 number-- 系统生成]
input_n[/ 输出数字 n /]
%% 定义判断条件
n_eq_number?{n == number?}
n_lt_number?{n < number?}
continue?{持续?}
%% 提醒
ALERT_gt[/ 提醒数字大了 /]
ALERT_eq[/ 提醒数字正确 /]
ALERT_lt[/ 提醒数字小了 /]
START --> gen_number --> input_n
input_n --> n_eq_number?
n_eq_number? --> | 是 | ALERT_eq --> continue?
n_eq_number? --> | 否 | n_lt_number?
n_lt_number? --> | 是 | ALERT_lt
n_lt_number? --> | 否 | ALERT_gt
n_lt_number? --> input_n
continue? --> | 是 | gen_number
continue? --> | 否 | END
逻辑有待优化。
2. 注册登录逻辑
1. 注册
graph TD
START([开始])
END([完结])
input[/ 输出帐号密码 /]
START --> input
input --> pw_pair?{明码是否合乎格局?}
pw_pair? --> | 否 | input
pw_pair? --> | 是 | user_pair?{帐号是否合乎格局?}
user_pair? --> | 是 | get_code[获取验证码]
user_pair? --> | 否 | input
get_code --> input_code[/ 输出验证码 /]
input_code --> code_pair?{验证码是否正确?}
code_pair? --> | 是 | success[注册胜利]
success -.- | 存储 | database[(用户数据库)]
code_pair? --> | 否 | 记录验证码谬误次数 --> try_more?{尝试次数过多?}
try_more? --> | 是 | will_END[限度获取验证码次数, 禁止注册] --> END
try_more? --> | 否 | en_time?{是否距离 60s 获取验证码?}
en_time? --> | 是 | get_code
en_time? --> | 否 | wait_time[期待 60s] --> get_code
success --> END
graph TD
START([开始])
END([完结])
input[/ 输出帐号密码 /]
START --> input
input --> pw_pair?{明码是否合乎格局?}
pw_pair? --> | 否 | input
pw_pair? --> | 是 | user_pair?{帐号是否合乎格局?}
user_pair? --> | 是 | get_code[获取验证码]
user_pair? --> | 否 | input
get_code --> input_code[/ 输出验证码 /]
input_code --> code_pair?{验证码是否正确?}
code_pair? --> | 是 | success[注册胜利]
success -.- | 存储 | database[(用户数据库)]
code_pair? --> | 否 | 记录验证码谬误次数 --> try_more?{尝试次数过多?}
try_more? --> | 是 | will_END[限度获取验证码次数, 禁止注册] --> END
try_more? --> | 否 | en_time?{是否距离 60s 获取验证码?}
en_time? --> | 是 | get_code
en_time? --> | 否 | wait_time[期待 60s] --> get_code
success --> END
2. 登录
graph TD
subgraph db [数据库]
db_user[(用户数据库)]
db_login[(已登录用户数据库)]
end
START([开始])
END([完结])
input[/ 输出帐号密码 /]
START --> input
input --> get_code[获取验证码]
get_code --> input_code[/ 输出验证码 /]
input_code --> code_pair?{验证码是否正确?}
code_pair? --> | 是 | pw_pair[从数据库匹配帐号密码]
pw_pair -.- | 查找 | db_user
pw_pair --> pw_pair?{帐号密码匹配?}
pw_pair? --> | 是 | success[登录胜利]
success -.- | 存储 | db_login
pw_pair? --> | 否 | input
code_pair? --> | 否 | 记录验证码谬误次数 --> try_more?{尝试次数过多?}
try_more? --> | 是 | will_END[限度获取验证码次数, 禁止登录] --> END
try_more? --> | 否 | en_time?{是否距离 60s 获取验证码?}
en_time? --> | 是 | get_code
en_time? --> | 否 | wait_time[期待 60s] --> get_code
success --> END
graph TD
subgraph db [数据库]
db_user[(用户数据库)]
db_login[(已登录用户数据库)]
end
START([开始])
END([完结])
input[/ 输出帐号密码 /]
START --> input
input --> get_code[获取验证码]
get_code --> input_code[/ 输出验证码 /]
input_code --> code_pair?{验证码是否正确?}
code_pair? --> | 是 | pw_pair[从数据库匹配帐号密码]
pw_pair -.- | 查找 | db_user
pw_pair --> pw_pair?{帐号密码匹配?}
pw_pair? --> | 是 | success[登录胜利]
success -.- | 存储 | db_login
pw_pair? --> | 否 | input
code_pair? --> | 否 | 记录验证码谬误次数 --> try_more?{尝试次数过多?}
try_more? --> | 是 | will_END[限度获取验证码次数, 禁止登录] --> END
try_more? --> | 否 | en_time?{是否距离 60s 获取验证码?}
en_time? --> | 是 | get_code
en_time? --> | 否 | wait_time[期待 60s] --> get_code
success --> END
在绝对简单的逻辑下,整体绘图有些芜杂。
小结
流程图不适用于过于简单的逻辑,对于简单的逻辑会有些表现力有余。前一章的登录界面我绘制了屡次,包含一张图体现登录注册登出等性能(应用 subgraph
)当绘制实现之后,只管伪代码很容易了解,图像却盘根错节。
流程图更实用于体现逻辑关系,对于程序中一个性能进行形容(面向过程),而状态变动却不好表白。这又得引出一个状态流图。
而面向对象的类图又须要 UML
进行形容。
目前流程图可用于简略的繁多性能形容中,其余须要后续再进行总结。一个残缺的利用不会这么简略。