一个简单的联动示例
示例中代码分析
// 以上示例的伪代码实现class Main extends PurComponents {constructor() {this.state = {A: '',B: '',C: '',}}// 响应逻辑handleAChange = (e) => {// 1.数据源筛选const { target: { value } } = e;// 2.双向绑定,组织数据结构let stateOptions = {A: value;};// 3.数据联动if (value === '1') {stateOptions = {...stateOptions,B: '',C: '',}}// 4.更新数据this.setState(stateOptions);};// UI组件render() {<div className="pic-wrapper"><PicPlayer ... /></div><div className="task-oper"><Text>标牌是否是施工场景</Text><ButtonGroup onChange={(e) => this.handleAChange(e)} />...<ButtonGroup disabled={A !== '2'} ... />...<ButtonGroup disabled={B !== '2'} ... /></div>... bla bla bla}}
由上方伪代码可以看到,一个车间的实现分为:UI + 逻辑
在可视化搭建中,UI部分和简单交互由组件内部实现,跨组件的逻辑部分则由事件回调实现,回调函数可以拆分为以下四部分主体功能和相关概念:
数据筛选:从函数参数中筛选需要的数据(涉及事件驱动的概念)
双向绑定:受控组件由外部数据驱动,状态变化后需要更新依赖的数据源(受控组件,双向绑定,不可变原则)
数据联动:其它数据的更新,组件间的联动通信;(业务逻辑)
数据更新:前端框架Api;
示例中基本概念如何简化的思考
针对事件驱动中回调函数中的数据筛选能力,我们开发了数据筛选器,在设计页面的组件设置器中用树形结构静态声明函数参数,用户只需选择对应的参数即可实现类似数据解构和赋值的功能
针对双向绑定,数据联动,immutable不可变原则,我们约定了简洁的数据存储语法,并针对此语法开发了特定的语法的解析插件,具体设计如下:
页面中一个组件状态变更触发联动其它组件状态变化的场景,我们认为这是一个组件的状态变更过程的"副作用"saveEffect;
每一条"副作用"包含三部分,分别是源数据,目标数据,转换逻辑,以上面联动为例:源数据A, 目标数据B, 转换逻辑是当A为1时,B清空, 对应数据结构是:
一个"副作用"对象由三部分构成
{ // 源数据 fromPath: 'e.target.value', // 目标数据 toPath: 'state.B', // 转换逻辑 formatFunc: 'function switchStoreValue(value, state) { return A == '1' ? '' : state.B };'}
saveEffect 副作用对象的简单示例
变更前全局数据state = { temp: { imageIndex: 0, }, workResult: { imageList: [ { attr1: 1, attr2: 2, }, ... ] }}
用户确定的saveEffect对象{ 源数据 fromPath: 'value' // 1 目标数据 toPath: 'workResult.imageList[state.temp.imageIndex].activeKey'; 默认值,用户无须书写 formatFunc: 'function switchStoreValue(value, state) { return value }';}
无转换逻辑,则经过插件解析后会生成以下结构并merge到state中{ temp: { imageIndex: 0, }, workResult: { imageList: [ { attr1: 1, attr2: 2, ... activeKey:1 }, ... ] }}
一个线上车间的例子
使用saveEffect设置器节省代码的前后对比,以引导线内容车间为例,我们需要为一个引导线方向赋值一个属性,UI操作如下图,选中车道,更新车道的类型
function handleButtonGroupClick(value) { // 获取当前选中的箭头选项 const { arrowList, currentIndex } = this.state; const currentArrow = arrowList[currentIndex]; // 数据更新 const newArrow = { ...currentArrow, type: value }; // 数据不可变; const newArrowList = arrowList.slice(0, currentIndex).concat([newArrow]).concat(arrowList.slice(currentIndex + 1)); // lowcode API更新数据 this.setState({ arrowList: newArrowList });}
state.arrowList[state.currentIndex].type = value
procode组件如何接入saveEffect
一个普通的组件是由userInterface 和 api驱动组件内部逻辑的运行;
saveEffect可以通过lowcode的setter层以api(props)的方式动态注入,然后在onChange等对外的接口中抛出即可,完全不影响组件的内部逻辑;
组件抛出value和saveEffect后,系统会自动调用我们开发的解析插件进行数据解析和保存,从而实现组件的"副作用"间联动效果;
《阿里低代码引擎》:https://lowcode-engine.cn/docV2/intro
《设置器扩展》:https://lowcode-engine.cn/docV2/cl03wo_nmhznb
《setter开发调试》:https://lowcode-engine.cn/docV2/ulvlkz
《物料规范》:https://lowcode-engine.cn/material
《阿里低代码引擎使用文档》:https://www.yuque.com/lce/doc
往期推荐
低代码开发师(高级)实战教程
低代码开发是指无需编码或通过少量代码,就可以快速生成应用程序的新型开发方式。“低代码开发师(高级)”针对有IT技术背景的人群,旨在提升低代码开发技能,通过场景化的实践,让读者具备系统之间的互联互通能力,逐步成为低代码专家。本书基于”低代码开发师(高级)认证“的课程内容,对应每个场景化的实践,提供了配套的实战指导教程,便于读者根据详细的步骤描述完成应用的创建。
点击阅读原文查看详情。