在實際的項目中,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表單(四)