注:本文使用的Formily为v1版本,21年4月中旬阿里团队已经推出v2版本 https://v2.formilyjs.org/ ,但是跨度非常大,为Breaking change
,相当于框架底层完全重构,对于v1版本的项目来说迁移成本非常大。
背景
https://formilyjs.org/#/bdCRC5/dzUZU8il
这里引用官网的描述:
Formily 是一个由阿里巴巴集团多部共建的面向中后台复杂场景的表单解决方案,它也是一个表单框架。
- 在复杂联动场景下更加清晰简单的描述联动的方式
- 在超多表单项场景下可以获得更好的表单操作性能
- 在跨终端场景下实现通用表单解决方案
Formily v1
提供给了我们3种React
的UI
框架
以下这些UI
框架经过formily
的二次封装,UI组件经过封装后,完美兼容了Formily
3种UI
框架分别为:
😊 Antd的Formily API文档
官方文档中并没有介绍基于JSON Schema
使用自定义组件的方法,但是给出了
1.基于JSX
表单的自定义组件制作方法, 理解表单扩展机制(虽然文档依旧欠缺,不过库的TypeScript
的类型做的还算很不错的,相当于一份文档吧)
2.实现超复杂自定义组件,但是该文档并不是很实用,由于我们是JSON Schema
开发模式,用useFromEffects
来控制state
显然不现实
制作自定义组件
这里以基于Antd
二次封装Radio
业务组件举例
在容器中引入自定义组件
首先,为了使用JSON Schema
模式,我们使用SchemaForm
组件。
1 2 3 4 5 6 7 8 9 10
| <SchemaForm components={components} onSubmit={onSubmit} expressionScope={createRichTextUtils(history)} schema={formData.schema} onChange={onCheckCanClickNextStep} actions={actions} onValidateFailed={onValidateFailed} > </SchemaForm>
|
可以注意到,props
有一个属性为components
,该属性代表了全部JSON Schema
通过x-component
可以使用的组件们。
components
对象如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import CustomRadio from '../../custom-components/CustomRadio/CustomRadio'; import 'xxx' from 'xxx'
const components = { CustomRadio, Input, Radio: Radio.Group, Checkbox: Checkbox.Group, TextArea: Input.TextArea, NumberPicker, Select, Switch, DatePicker, DateRangePicker: DatePicker.RangePicker, YearPicker: DatePicker.YearPicker, MonthPicker: DatePicker.MonthPicker, WeekPicker: DatePicker.WeekPicker, TimePicker, TimeRangePicker: TimePicker.RangePicker, Upload, Range, Rating, Transfer, };
|
我们在对象中添加一个CustomRadio
,至此成功引入了一个我们要自定义的组件
在真正开始写组件逻辑之前,你需要了解JSON Schema
的Schema
规范,这一部分
实际上比如Antd
的Form
组件,大体构成为
1 2 3 4 5 6 7 8 9 10
| <Form> <Form.Item className="form-item" label="test_radio" name="test_radio" rules={[{ required: true }]} > <CustomRadio terminalValue={[ 1 ]} /> </Form.Item> </Form>
|
那么如何用JSON
去描述这一行为呢?Formily
约定的Schema
如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| { "type": "object", "properties": { "test_radio": { "key": "test_radio", "type": "number", "title": "测试customRadio", "name": "test_radio", "required": true, "enum": [ { "label": "yes", "value": 1 }, { "label": "no", "value": 0 } ], "x-props": { "itemClassName": "form-item" }, "x-component": "CustomRadio", "x-component-props": { "terminalValue": [ 1 ] }, "default": 1 }, } }
|
简单解释一下:
x-props
表示<Form.item />
的props
x-component-props
表示表单UI
组件的props
制作表单组件
为了方便,我们直接在Antd
的Radio
组件基础上封装我们的业务Radio组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import styles from './CustomRadio.module.scss'; import { Radio } from 'antd'; import { useEffect, useState } from 'react';
export default ({ onChange, terminalValue = [], dataSource = [], value, ...rest }) => { const [radioValue, setRadioValue] = useState(value);
const onChangeRadioGroup = event => { const value = event.target?.value;
if (terminalValue.includes(value)) { }
setRadioValue(value); onChange(value); };
return ( <div className={styles.container}> <Radio.Group onChange={onChangeRadioGroup} value={radioValue}> {dataSource.map((radio, index) => ( <Radio key={index} value={radio.value}> {radio.label} </Radio> ))} </Radio.Group> </div> ); };
|
在Formily
框架中,在调用组件时,会自动注入几个属性
onChange
onBlur
onFocus
value
dataSource
- 我们在
x-component-props
层定制的属性
还有其它的默认属性们
字段 |
作用 |
onChange |
调用该方法才可以真正对Form 实例对象上的对应name 表单项的value 进行修改 |
value |
对应着JSON中的default 字段改 |
dataSource |
比如在Radio中,就是通过JSON描述的Enum值 |
自定义属性 |
- |
注入业务逻辑
我们主动去监听Radio.Group
的onChange
事件,当其value
值满足我们的业务逻辑时,我们触发相关业务逻辑。
结语
至此,我们完成了一个最基础的业务组件。如果还有什么疑问的话,可以参考 理解表单扩展机制 。
吐槽:简单看了一下v2的介绍,Formily官方文档中描述的意思是,官方也意识到了v1版本组件扩展的问题,所以在v2版本完全重构了。