JSON生成Form表單(三)

container表單組件

在實際的項目中,JSON表單提供的表單組件是遠遠不夠的,並且提供表單組件是一件低效的事,目前Ant Design組件庫提供的表單組件就已經很實用了。react

因此container提供了一套規則來自定義表單組件,來知足實際項目中複雜且靈活的表單組件使用場景,container主要的做用有如下幾點:json

  1. 自定義表單組件,例如圖片上傳組件
  2. 添加表單組件庫,例如Ant-Design
  3. 處理控制邏輯和聯動邏輯

自定義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只能這樣自定義使用咱們的表單組件,那麼它的實用意義的確不大。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

modifyDataFn

經過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嵌套組件配置

若是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表單(四)

相關文章
相關標籤/搜索