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