Context (ctx) 上下文对象
Context对象(ctx)是渲染引擎RE结合页面设计内容与宜搭默认配置,生成的页面级上下文对象。Context对象中整合了RE封装的各个模块与模块API,用以辅助开发定制业务功能。
设计器中的各个回调函数所接受的参数中,都会包含ctx此参数(但略有不同,详细见 代码编辑入口)。
此外,ctx还可以通过 window.LeGao.getContext() 全局方法进行获取(通常用于 动作面板 或 浏览器控制台)。
ctx.getStore()
获取当前页面的存储模型(Store),通常可直接使用 ctx.store 来代替。
ctx.getFieldData()
获取当前页面的所有表单数据。
此数据中包含隐藏的表单组件数据,是未经ctx.getFieldDataExcludeHidden()处理的原始数据。
ctx.getFieldDataExcludeHidden()
获取当前页面的表单提交数据。
此方法将对页面的所有表单数据进行过额外处理,并返回最终提交的页面数据。具体的额外处理逻辑,另见 组件状态。
ctx.execAction(fnName, …args)
动作面板相关。
执行 js 动作面板中的事先定义好,且被export导出的函数。
若fnName对应的函数不存在,则抛出一个warning并返回false。若存在,则返回fnName方法执行后return的值。
警告:ctx.execAction(fnName, …args) 存在旧API兼容逻辑,即如果args[0] !== window.LeGao.getContext(),则默认将第一个参数补充为ctx,原有的args顺延至后一位。
ctx.getDataPool()
获取当前页面的数据池(DataPool),通常可直接使用ctx.dp来代替。
ctx.getCurrentPageId()
获取当前页面的唯一标识,即formUuid。
ctx.getLocale()
获取当前页面的本地语言环境 ( ‘zh_CN’ or ‘en_US’ )。
ctx.getDevice()
获取当前页面的所在的设备环境 (‘PC’ or ‘MOBILE’)。
ctx.getComponentInstance(fieldId)
根据组件的fieldId,返回实际页面上的组件实例引用(相当于React中的ref引用)。
需要等待组件渲染完成。一般不推荐使用。
Store 存储模型
存储模型(Store)是页面上所有组件状态管理器(State)的集合。
RE在渲染各个组件之前,会为每个组件单独创建状态管理器(State),在此State中存储对应组件的「属性」、「值」、「状态」等可控数据,并将这些数据的控制转交给State,封装对数据进行增删改查操作的API。
组件的唯一标识即为组件的fieldId。
ctx.store.get(fieldId)
根据指定的fieldId获取对应的组件State。
ctx.store.getData() or ctx.store.getData(key)
获取所有或指定fieldId/key中存储的可控数据值。
参数key为可选参数,且支持通过’/‘拼接多级字段
若参数key不存在,则返回以组件fieldId为key,组件可控数据对象为value的对象。
若参数key存在,则查找key中fieldId对应的State,并根据层级找到对应数据返回。未找到指定数据则返回null。
State 状态管理器
状态管理器State负责管理组件属性、状态、值等数据,与组件视图直接绑定。
通常可由 ctx.store.get(fieldId) 获取到组件的state。在某些触发的回调函数中,state直接作为回调函数的参数之一,或者作为回调函数重新封装过的ctx的子属性存在。
state.getData() or state.getData(key)
获取所有或指定key对应的可控数据的值。
与ctx.store.getData(key)功能类似,参数key也支持通过’/‘拼接多级字段。
state.getData() 列出的可控数据项,一般具有与组件的props一一对应的绑定关系,在调用state.set/merge等API时会同步修改组件的实际视图。
通用场景下,需要修改的数据项:
- 组件值:’fieldData/value’
- 显示隐藏状态:’behavior/fieldBehavior’
- 选择类组件的选项:’options’
- 文本、链接组件(基础组件)的文本:’content’
state.getVal()
获取当前表单组件的值。
实际相当于调用state.getData(‘fieldData/value’);
state.setVal(value)
设置当前表单组件的值。
实际相当于调用state.set(‘feildData’, { value: ‘value’ })。与merge方式不同,set设置值的方式为全量覆盖,因此只会保留下value字段。
state.getBehavior()
获取当前组件的显示状态标记。
返回值枚举:{ 通常: ‘NORMAL‘, 只读: ‘READONLY‘, 禁用: ‘DISABLED‘, 隐藏: ‘HIDDEN‘ }
表单类组件存在通常、只读、禁用、隐藏四个状态,非表单组件一般只有通常/隐藏两个状态。
实际相当于调用 state.getData(‘behavior/fieldBehavior’)。behavior属性下除fieldBehavior以外的字段目前没发现作用,建议无视。
state.setBehavior(val)
设置当前组件的显示状态标记。
实际相当于调用state.set(‘behavior’, { fieldBehavior: ‘状态’ })。set设置值的方式为全量覆盖,因此只会保留下fieldBehavior字段,而其它消失的字段暂未发现作用。
state.merge(key, value)
修改指定key对应的可控数据的值。依据当前值的数据类型,判断用value进行合并或覆盖。
注意:此处key 不支持 用’/‘拼接多级
在修改非组件值或显示状态的数据时 (例如’options’),推荐使用,需要注意以下逻辑:
- 当前值类型为Object,参数value类型同为Object,按Object.assign方式合并数据
- 当前值类型为Object,参数value类型同为null或undefined,不进行改动
- 此外,用value对当前值进行全量覆盖
state.forceValid()
强制触发当前表单组件的校验。
通常不需要使用。在调用ctx.getFieldDataExcludeHidden()或ctx.getFieldData()获取提交数据时,所有表单组件会默认执行校验并在errorMsg中返回错误信息的字符串或字符串数组。
使用场景示例:PC端根据接口数据对组件setVal后,期望展示校验信息。
state.get(key)
获取指定key对应的可控数据的实例对象(这里是Atom类的实例)。
参数key支持通过’/‘拼接多级字段。不常使用,仅进行介绍。
Atom实例是State操作数据时底层实际执行操作的对象,封装了与State类似的get、set、merge、getData()等API。通常可通过state.get(key).getData()获取数据,或通过state.get(key).merge(‘targe’, value)来控制修改的精细度。
state.set(key, value)
设置当前key对应的可控数据的值。
此方法是与state.getData(key)对应的设置方法,并非state.get(key)对应的设置方法。
参数key支持通过’/‘拼接多级字段。
此方法设置的data为全量覆盖,因此可以将一个Object类型的数据直接设置为null。
明细组件 State
// 在ctx.store中,明细组件的State以及其内部的子组件会被视为一个整体。
// 明细中的子组件会因为新增一条而在页面上出现多个,因此组件的fieldId无法对应唯一的state。
"正因如此,ctx.store.get(fieldId)方法无法拿到明细中子组件的state"
// 目前如果需要修改明细中的子组件,可以拿到明细组件的fieldData/value
// 在此对象数组中找到对应条数的组件fieldId的可控数据map
// 进行修改后用明细组件的state.set/merge重新修改组件整体。
// 强烈建议在明细的state.set/merge操作前,调用state.setCurrentTargetDisable(true);
// 并在明细的state.set/merge操作后,调用state.setCurrentTargetDisable(false);
// 以解决目前明细可能会出现的子组件事件重复触发的性能问题
"见以下示例一"
// 若只需要在明细中子组件发生变更时,获取当前所在条数下的其它组件数据
// 则可以在子组件的动作设置中配置export方法或自定义方法
// 此方法接受的ctx参数中会附加一个额外的RE动态注入的环境ctx.scope
// ctx.scope相当于事件触发时的局部store,ctx.scope.get('fieldId')可获取当前条目下其它组件的State
"见以下示例二"
// 若明细表格方式下,内部子组件的显隐状态通过绑定变量控制
// 改变变量的值时,则可以调用ctx.store.get('fieldId').forceUpdate()来触发明细重新渲染
"见以下示例三"
示例一:
示例二:
示例三:
DataPool 数据池
数据池DataPool归属于上下文对象Context的一个子模块(ctx.dp),是一个页面级的全局数据管理中心。
出于目前代码编写碎片化的现状,如果要在不同代码块间共享数据,则会不可避免的污染全局环境,而数据池正是解决此副作用的一种方式。
ctx.dp.getValue() or ctx.dp.getValue(name)
获取所有或指定name的数据源的值。
ctx.dp.setValue(data) or ctx.dp.getValue(name, value)
设置指定的变量数据源的值。
设置非变量类型的数据源,没有效果。因此目标数据源未定义,同样没有效果。
支持 Object :: data 或 String :: name, any :: value 两种参数方式。
注意1:返回一个Promise,resolve方法默认参数为所有数据源的值(同 ctx.dp.getValue()
)。设置的值需要再Promise resolve后才能获取到,否则仍然是旧的值。
注意2:此API会使 变量 系统对所有 ${} 中代码进行自检执行,有变更的内容将触发相关更新。
dp.exec(name, params)
触发指定的远程数据源的接口请求。
Object :: params 中指定的参数,默认会与远程数据源中配置的参数进行合并(Object.assign)。
一般用于触发加载类型为「手动」的远程数据源接口。
返回的 Promise 与 ctx.dp.setValue
不同,resolve方法默认参数仅为name对应的数据源的值。
同样会触发变量系统的自检。
远程数据源存在缓存机制,相同参数的接口请求只会触发一次。如果期望每次 dp.exec
都能重新发送请求,请确保请求参数存在差异,例如添加值为时间戳的参数。