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表单(四)

相关文章
相关标签/搜索