在实际的项目中,JSON表单提供的表单组件是远远不够的,并且提供表单组件是一件低效的事,目前Ant Design组件库提供的表单组件就已经很实用了。react
因此container提供了一套规则来自定义表单组件,来知足实际项目中复杂且灵活的表单组件使用场景,container主要的做用有如下几点:json
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方法的参数: 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只能这样自定义使用咱们的表单组件,那么它的实用意义的确不大。segmentfault
在个人团队项目中,你们使用的都是Ant-Design
组件库,那么接下来咱们就把Ant-Design
组件库接入到JSON表单中。缓存
首先咱们建立一个组件文件,取名为antd-components.js:antd
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)引入该组件库:ui
import Form from 'json_transform_form' import components from './antd-components' From.createCustomComp(components)
这样咱们就能够在项目的任何地方使用该组件库:spa
{ formKey: 'test-form', ... config: [ { type: 'antd-input', // 使用antd-input表单组件 dataKey: 'name', label: 'Param', customConfig: {}, // 自定义配置 } ] }
你看这样container的实用价值就体现出来了,复杂表单组件的自定义只须要编写一次,接下来的重复使用,只须要传入相应的配置便可。code
跨项目的共用表单组件也是经过该方式实现,维护一个不一样项目均可引用的组件库文件,将经常使用的复杂表单组件,抽象在该组件库文件里,而后在不一样项目初始化时引入进来,这样就能在不一样项目中共用表单组件。component
经过container使用共用表单组件时,存在一个问题,那就是没法再次自定义表单组件的提交事件,例如:使用上面的antd-input
自定义组件,该组件自动提交本组件的数据,可是若是想联动处理其余表单,修改其余表单组件的数据,这个时候不能在组件配置里重写render,由于组件配置里的render会覆盖掉组件库中的render,致使抽象出来的渲染方法失效。orm
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表单组件里还含有其余表单组件,这时直接经过组件配置去渲染无疑能节约很多的工做量。
{ 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表单(四)