1. 准备工作
安装并启动项目
$ git clone git@github.com:imgcook/imove.git $ cd imove $ npm install $ npm run example
项目成功启动后,浏览器会自动打开 http://localhost:8000/,如下所示
2. 绘制流程图
项目启动成功后,可以从左侧面板中依次拖动节点至中间的画布,从而完成流程图的绘制工作
2.1 创建节点
当左侧面板中的节点被拖入中间的画布时,即完成一个节点的创建
2.2 节点类型
在 iMove 中,我们将流程图的节点一共分为以下 3 种类型:
- 开始节点:逻辑起始,是所有流程的开始,可以是一次生命周期初始化/一次点击
- 行为节点:逻辑执行,可以是一次网络请求/一次改变状态/发送埋点等
- 分支节点:逻辑路由,根据不同的逻辑执行结果跳转到不同的节点
(注:一条逻辑流程必须以 开始节点 为起始)
根据上述的规范描述,我们可以绘制出各种各样的逻辑流程图,例如 获取个人数据 的逻辑流程图如下所示:
2.3 配置节点
接下来,我们需要依次选中图中的节点,完成右边面板中的基础配置信息填写
通常来说,基础信息配置使用频率最高的有:
- 显示名称:更改节点名称
- 代码:编辑节点代码
- 逻辑触发名称:开始节点类型专属配置,项目代码使用时根据这个值触发逻辑调用
2.4 节点代码规范
点击编辑按钮,可打开代码编辑器
每个节点的代码等价于一个 js 文件,因此你不用担心全局变量的命名污染问题,甚至可以 import 现有的 npm 包,但最后必须 export 出一个函数。需要注意的是,由于 iMove 天生支持节点代码的异步调用,因此 export 出的函数默认是一个 promise。
就拿 是否登录 这个分支节点为例,我们来看下节点代码该如何编写:
export default async function() { return fetch('/api/isLogin') .then(res => res.json()) .then(res => { const {success, data: {isLogin} = {}} = res; return success && isLogin; }).catch(err => { console.log('fetch /api/isLogin failed, the err is:', err); return false; }); }
注:由于该节点是 分支节点,因此其 boolean 返回值决定了整个流程的走向
2.5 节点间数据通信
最后,我们再来看下节点之间是如何数据通信的。
在 iMove 中,数据是以流(pipe)的形式从前往后进行流动的,也就是说前一个节点的返回值会是下一个节点的输入。不过也有一个例外,由于 分支节点 的返回值会是 boolean 类型,因此它的下游节点拿到的输入必将是一个 boolean 类型值,从而造成数据流的中断。为此,我们进行了一定的改造,分支节点的作用只负责数据流的转发,就像一个开关一样,只决定数据流的走向,但不改变流向下游的数据流值。
因此,前文例子中的 请求profile接口 和 返回数据 两个节点会成为数据流的上下游关系。我们再来看下他们之间是如何进行数据通信的:
// 节点: 请求profile接口 export default async function() { return fetch('/api/profile') .then(res => res.json()) .then(res => { const {success, data} = res; return {success, data}; }).catch(err => { console.log('fetch /api/isLogin failed, the err is:', err); return {success: false}; }); }
// 节点: 接口成功 export default async function(ctx) { // 获取上游数据 const pipe = ctx.getPipe() || {}; return pipe.success; }
// 节点: 返回数据 const doSomething = (data) => { // TODO: 数据加工处理 return data; }; export default async function(ctx) { // 这里获取到的上游数据,不是"接口成功"这个分支节点的返回值,而是"请求profile接口"这个节点的返回值 const pipe = ctx.getPipe() || {}; ctx.emit('updateUI', {profileData: doSomething(pipe.data)}); }
如上代码所述,每个下游节点可以调用 ctx.getPipe 方法获取上游节点返回的数据流。另外,需要注意的是 返回数据 节点的最后一行代码 ctx.emit('eventName', data) 需要和你项目中的代码配合使用,会在后文提到。
3. 项目中使用流程图编译生成的代码
在完成所有节点的配置之后,需要对流程图进行编译,才能在你的项目中使用生成的代码。目前支持两种出码方式:在线出码、本地命令行出码
3.1 在线出码
点击页面右上方的导出按钮后,可以在弹窗内选择导出 代码,此时流程图编译后的代码将以 zip 包的形式下载到本地,你可以解压后再引入项目中使用。
3.2 本地命令行出码
安装 CLI
$ npm install -g @imove/cli
进入项目根目录,imove 初始化
$ cd yourProject $ imove --init # 或 imove -i
本地启动开发模式
$ imove --dev # 或 imove -d
本地启动成功之后,可以看到原来的页面右上角会显示连接成功
此时页面上触发 保存快捷键 Ctrl + S 时,可以看到当前项目的 src 目录下会多出一个 logic 目录,这就是 imove 编译生成的代码,此时你只要在你的组件中调用它即可。
// file: src/App.js import React, {useState, useEffect} from 'react'; import logic from './logic'; const App = () => { const [state, setState] = useState({}); useEffect(() => { // NOTE: 监听 updateUI 事件, logic.on('updateUI', (data) => { const {profileData} = data || {}; setState(profileData); }); // NOTE: 调用逻辑 logic.invoke('getProfile'); }, []); const {profileData} = state; const {nickName, avatar} = profileData || {}; return profileData && ( <div> <span>{nickName}</span> <img src={avatar} /> </div> ); }; export default App;
如上代码所示,需要注意两点:
- 通过 logic.on 方法监听事件,事件名和参数与流程图中节点代码的 ctx.emit 相对应
- 通过 logic.invoke 方法调用逻辑,事件名与流程图中的开始节点的 逻辑触发名称 相对应,不然会调用失败