container表单组件
在实际的项目中,JSON表单提供的表单组件是远远不够的,而且提供表单组件是一件低效的事,目前Ant Design组件库提供的表单组件就已经很实用了。
所以container提供了一套规则来自定义表单组件,来满足实际项目中复杂且灵活的表单组件使用场景,container主要的作用有以下几点:
- 自定义表单组件,例如图片上传组件
- 添加表单组件库,例如Ant-Design
- 处理控制逻辑和联动逻辑
自定义input组件
import {Input} from 'antd'
{
formKey: 'test-form',
...
config: [
{
type: 'container',
dataKey: 'name',
label: 'Param',
customConfig: {
// 自定义的配置
},
render: (curData, config, {changeFn, changeDataFn, getFocus, loseFocus, JSONForm, error, assistData, data}) => {
return <Input value={curData}
{...config.customConfig}
onFocus={getFocus}
onBlur={loseFocus}
placeholder={config.placeholder ? config.placeholder : ''}
style={{borderColor: !!error ? '#f5222d' : ''}}
onChange={event => changeFn(event.target.value)} />
}
}
]
}
render方法
render方法的参数:
1:curData,该container组件对应的值
2:config,该container的组件配置,config.customConfig是自定义配置,里面可以传入antd的input组件的配置
3:changeFn,changeDataFn:提交数据的方法, 两者的区别在于changeFn只能提交当前表单组件的值,changeDataFn能自定义提交的值
changeFn(value, [callback])
changeDataFn(key, value, [callback])
4:getFocus,loseFocus:用来触发数据校验,loseFocus方法触发校验,getFocus方法来取消报错信息
5:JSONForm是用来在render方法里渲染组件配置,即在container里嵌套组件配置
6:error:校验报错
7:assistData,data: 逻辑数据和表单数据
表单组件库
其实你会发现,container自定义的表单组件并不比原始表单简单,估计你会怀疑这种实现方式的价值。的确,如果container只能这样自定义使用我们的表单组件,那么它的实用意义的确不大。
在我的团队项目中,大家使用的都是Ant-Design
组件库,那么接下来我们就把Ant-Design
组件库接入到JSON表单中。
首先我们创建一个组件文件,取名为antd-components.js:
import React from 'react'
import { Input } from 'antd'
export default [
{
type: 'antd-input', // 声明为antd-input的自定义表单组件
render: (curData, config, {changeFn, getFocus, loseFocus, error}) => {
return <Input value={curData}
onFocus={getFocus}
{...config.customConfig}
onBlur={loseFocus}
placeholder={config.placeholder ? config.placeholder : ''}
style={{borderColor: !!error ? '#f5222d' : ''}}
onChange={event => changeFn(event.target.value)} />
}
}
]
然后在我们的项目初始化的文件中(init.js)引入该组件库:
import Form from 'json_transform_form'
import components from './antd-components'
From.createCustomComp(components)
这样我们就可以在项目的任何地方使用该组件库:
{
formKey: 'test-form',
...
config: [
{
type: 'antd-input', // 使用antd-input表单组件
dataKey: 'name',
label: 'Param',
customConfig: {}, // 自定义配置
}
]
}
你看这样container的实用价值就体现出来了,复杂表单组件的自定义只需要编写一次,接下来的重复使用,只需要传入相应的配置即可。
跨项目的共用表单组件也是通过该方式实现,维护一个不同项目都可引用的组件库文件,将常用的复杂表单组件,抽象在该组件库文件里,然后在不同项目初始化时引入进来,这样就能在不同项目中共用表单组件。
modifyDataFn
通过container使用共用表单组件时,存在一个问题,那就是无法再次自定义表单组件的提交事件,例如:使用上面的antd-input
自定义组件,该组件自动提交本组件的数据,但是如果想联动处理其他表单,修改其他表单组件的数据,这个时候不能在组件配置里重写render,因为组件配置里的render会覆盖掉组件库中的render,导致抽象出来的渲染方法失效。
modifyDataFn用来自定义提交数据,只会覆盖render方法中的提交数据的功能。
{
formKey: 'test-form',
...
config: [
{
type: 'antd-input', // 使用antd-input表单组件
...
modifyDataFn: ({changeFn, changeDataFn}, {parent, self}) => {
changeDataFn('name', self.curDAta)
}
}
]
}
modifyDataFn的参数:
1:changeFn,changeDataF,提交数据的方法
2:parent,当该表单组件为form_array的子表单组件时,该值为form_array的组件数据
3: self,该表单组件的数据
处理控制逻辑和联动逻辑
在JSON表单的表单配置中,有assistData的选填字段,该字段为JSON表单内部处理复杂的控制逻辑所需的额外数据,该数据不会被提交和缓存。例如:在表单内存在一个刷新按钮,点击会刷新前一个表单组件的数据,其效果图如下:
表单中间的刷新按钮,可以认为是一个特殊的container表单组件,因此可以根据container来自定义该刷新按钮:
{
formKey: 'test-form',
assistData: {
refresh: false,
},
config: [
...
{
type: 'container',
dataKey: 'assistData.refreshParam',
style: {
...
},
render: (curData, config, {changeFn, changeDataFn}) => {
const handleClick = () => {
changeDataFn('assistData.refresh' ,true)
setTimeout(() => {
changeDataFn('assistData.refresh' ,false)
}, 1000 * 3)
}
return <React.Fragment>
{
config.index === config.parentData.length - 1 &&
<Popover placement="top" content="刷新param列表">
<Button shape="circle" loading={curData} onClick={handleClick}>{!curData && <Icon type="reload" />}</Button>
</Popover>
}
</React.Fragment>
}
},
]
}
上面的代码实现了刷新按钮点击刷新的动作,其刷新逻辑是assistData里的refresh字段控制。
注意:如果要使用assistData中的数据,其dataKey必须以assistData开头,且必须使用changeDataFn自定义提交assistData数据。
container嵌套组件配置
如果container表单组件里还含有其他表单组件,这时直接通过组件配置去渲染无疑能节约不少的工作量。
{
data: {
param: {
name: ''
}
},
config: [
{
type: 'container',
dataKey: 'param',
render: (curData, config, {changeFn, changeDataFn, JSONForm}) => {
return <div>
{
JSONForm([
{
type: 'input',
dataKey: 'name',
placeholder: '请输入param',
validate: ['required'],
}
])
}
</div>
}
]
}
JSONForm方法传入组件配置的列表就能渲染出表单组件来,需要注意的是,子表单组件的dataKey一定是基于父表单组件的。
JSON表单的实例方法请看下节的JSON生成Form表单(四)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。