首頁  >  文章  >  web前端  >  JSON產生Form表單的詳細解析(程式碼實例)

JSON產生Form表單的詳細解析(程式碼實例)

不言
不言轉載
2018-11-20 14:47:225643瀏覽

這篇文章帶給大家的內容是關於JSON產生Form表單的詳細解析(程式碼實例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

JSON表單

描述

#JSON表單是基於React的抽像元件,它可以把JSON資料格式描述的表單轉換成項目中的表單,它可以用簡短的幾行程式碼,快速的產生Form表單。
JSON表單的優點是:

  1. 可以快速建立一個表單

  2. 表單的資料、邏輯、檢視分離,方便抽離和進一步抽象

  3. 提供校驗、自動快取等額外功能,提升輸入體驗

  4. 可以跨專案的共用複雜的表單元件

原始表單的缺點

1:程式碼量龐大,開發效率低
每次開發一個表單頁的時候,都需要重複編寫表單元件及其互動事件的程式碼,這塊程式碼重複編寫且與主線業務邏輯無關,除此之外,表單的校驗、快取等額外功能,也需要不少的程式碼量,這樣就造成了一個表單頁的程式碼量龐大。

2:不便於抽離和進一步的抽象
在一個表單頁內,往往會將表單資料、表單元件、控制邏輯雜糅在一起,當發現某一個子功能在很多場景下都需要用到的時候,要把該子功能拆分出來發現並不容易,因為邏輯、資料、視圖的雜糅,導致想把子功能不受影響的剔除出來需要很仔細的檢查,這樣就導致功能的抽離和抽象的不便

3:維護成本高
這個和第二個問題是同樣的原因,這也是我的親身經歷,當我在專案中想優化一個小功能的時候,發現不只把之前的邏輯改沒了,還引出了不少的bug,這導致在一個邏輯很複雜的表單裡,維護變成了一件高危險工作。

4:需要額外處理校驗和快取等功能

一個栗子

const config = {
    formKey: 'example-form',
    data: {
        name: '',
        descr: '',
        typeName: ''
    },
    config: [
        {
            type: 'input',
            dataKey: 'name',
            label: 'param',
            placeholder: '请输入param',
            validate: ['required', /^[a-zA-Z_{}0-9]+$/g],
            style: {
                display: 'inline-block',
                width: 270,
            },
        },
        {
            type: 'select',
            dataKey: 'typeName',
            options: ['string', 'integer', 'float'],
            style: {
                display: 'inline-block',
                width: 100,
                margin: '0 15px'
            },
            validate: [{type: 'required', message: 'param类型不能为空'}]
        },
        {
            type: 'textarea',
            dataKey: 'descr',
            placeholder: '请输入param含义',
            label: 'param含义',
            validate: ['required'],
            style: {
                width: 385,
            }
        },
    ]
}

<from> this.FormWrap = ref} config={config}></from>

上面是用JSON描述的三個常用的表單元件組合成的表單,其效果圖如下:

JSON產生Form表單的詳細解析(程式碼實例)

JSON表單的格式

{
    formKey: 'paramAddForm',
    data: {},
    config: []
}
formKey className##data是表單的提交數據,有自動快取和校驗功能object-assisData 否用於表單控制邏輯的額外資料object-config是元件配置,表單元件的配置Array#-realTimeSubmit
是否必傳 說明 類型 #預設值
formKey
#否 是用來自動緩存,localStorage的key,不傳表示不自動快取 string -
用來加入一些自訂樣式 string -
######################################################## #否######表單是否即時提交,一般用於篩選表單######boolean#######false############

表单组件的配置

{
    type: 'input',
    dataKey: 'name',
    label: 'param',
    validate: ['required'],
    style: {}
}
属性 是否必传 说明 类型 默认值
type 表单组件的类型,其值可以为: input、select、textarea、form_array、container和一些自定义表单组件 string -
dataKey 指定表单组件值的key,可以为param.name.firstName形式 string -
label 表单组件的label string -
placeholder 表单组件的placeholder string -
validate 表单组件的校验规则 Array -
style 表单组件的布局样式 string -
options 当表单组件为select时,需要传入的options Array -
render 当type为container时,为自定义组件,render为渲染方法 Function -
preventSubmit 当realTimeSubmit为true时,控制当前表单组件是否实时提交 boolean false
children 当type为form_array时,children表示子组件配置列表 Array -
modifyDataFn 当type为自定义组件时,且需要覆盖render方法中的提交数据方法,可以使用modifyDataFn来重新自定义提交数据 Function -

关键字段解释

1. type

type是用来唯一表示表单组件类型的字段,其中JSON表单提供了三种默认的表单组件:input、select、textarea,还有两种复杂类型的表单组件:form_array、container。

form_array表单组件表示其数据结构为Array,含有增加项删除项的复合表单组件,该表单组件的配置里多一个children的字段,里面是每一项里面的表单组件配置的集合,其表单组件的效果如下图所示:

JSON產生Form表單的詳細解析(程式碼實例)

container是用来自定义表单的接口,具体用法参考下面具体的介绍。

2. validate

validate是校验表单组件数据正确性的字段,其值为数组,里面的数组元素可以为String、object、RegExp、Function。

JSON表单采用的是async-validator异步处理校验,在JSON表单内部会将validate传入的校验关键字解析为async-validator的rules。所以validate数组元素如果为object的话,其内容就是async-validator的rules。

1. 数组元素为string,其值可以为:
    string,值必须为string
    number,值必须为数字 
    required,值不能为空
    boolean,值必须为布尔值
    integer,值必须为整数形
    float,值必须为浮点型
    email,值必须为邮箱类型
2. 数组元素为object,其值为rules:
    {type: 'enum', enum: ['1', '2'], message: '值不在确定范围内'}
3. 数组元素为RegExp, validate: [/^[a-zA-Z_{}0-9]+$/g]
4. 数组元素为Function, validate: [ (rules, value, callback) => {}]

3. style

用来确定表单组件在表单内的布局样式,比如想让表单组件行内显示,且宽度为200,其style值如下:

{
    display: 'inline-block',
    width: 200
}

container表单组件

container表单组件是用来自定义表单组件的,它主要的作用有以下几点:

  1. 添加表单组件库,例如Ant-Design

  2. 自定义表单组件,例如图片上传组件

  3. 用来构建复杂的表单组件

  4. 处理控制逻辑和联动逻辑

使用栗子

import { Input, Select } from 'antd'
const Option = Select.Option
{
    type: 'container',
    dataKey: 'descr',
    style: {
        display: 'inline-block',
        width: 100,
        margin: '0 15px'
    },
    options: ['string', 'integer', 'float'],
    render: (curData, config, {changeFn, getFocus, loseFocus, error}) => {
        return <select> changeFn(value, () => {
                loseFocus()
            })}>
            {
                config.options && config.options.map((item, idx) => <option>{item}</option>)
            }
        </select>
    }
},

container表单组件只是多一个render渲染方法,里面可以自定义表单组件的渲染内容,render方法提供如下参数:

1. curData: 当前container组件的值,跟dataKey相关
2. config: 当前container组件的配置
3:{changeFn, changeDataFn, getFocus, loseFocus, error, JSONForm}
   changeFn, changDataFn是提交数据的方法,changeFn只能修改当前组件dataKey的值,changeDataFn可以修改data中任意字段的值,changeFn(value, [callback]), changeFn(dataKey, value, [callback])
   getFocus,loseFocus是自定义处理校验的字段,loseFocus是开始校验,getFocus是去掉校验的报错信息
   error是校验结果的报错信息
  JSONForm是在container中使用JSON表单的组件配置用来生成新的表单组件,意思里container中依然可以嵌套表单组件。

使用antd的组件库

JOSN表单只提供了input、select、textarea三种默认的表单组件,远远不够真实的项目中使用,所以我们可以将antd组件库中的组件封装到JSON表单中,这样我们就可以再项目中很快的使用antd中的组件。

antd-components.js

import React from 'react'
import { Input } from 'antd'
export default [
    {
        type: 'antd-input',
        render: (curData, config, {changeFn, getFocus, loseFocus, error}) => {
            return <input> changeFn(event.target.value)} />
        }
    }
]

我们在antd-components.js文件中声明一个antd-input的自定义组件,然后在JSON表单中引入该自定义表单组件:

init.js

import Form from 'Form'
import components from './antd-components'
From.createCustomComp(components)
const config = {
    formKey: 'paramAddFromAntd',
    data: {
        name: '',
    },
    config: [
        {
            type: 'antd-input',
            dataKey: 'name',
            label: 'Param',
            placeholder: '请输入param',
            validate: ['required', /^[a-zA-Z_{}0-9]+$/g]
        }
    ]
}
<from> this.FormWrap = ref} config={config}></from>

使用container来引入antd组件库,其原理就是通过container将antd组件封装成'antd-input'自定义组件,然后使用它,这种方式不仅可以用来封装组件库,还可以用来共享一些共用表单组件,可以将常用的复杂表单组件封装在一个共用文件里,然后在不同项目中引用,就可以跨项目共用表单组件。

在自定义组件中,如果需要自定义表单提交数据函数,但是又不能重写render方法以防覆盖原先的render方法,所以可以使用modifyDataFn方法来覆盖render中的提交数据部分。

modifyDataFn: ({changeFn, changeDataFn}, {parent, self}) => {
    let {parentData} = parent
    parentData = parentData.map(item => ({
        ...item,
        name: self.curData
    }))
    changeDataFn(parent.parentKey, parentData)
}

处理控制逻辑和联动逻辑

在JSON表单JSON配置中,有assistData的选填字段,该字段为JSON表单处理控制逻辑的额外数据,例如在表单内有一个刷新按钮,其实现代码如下:

{
    data: {},
    assistData: {
        refreshParam: false
    },
    config: [
        {
            type: 'container',
            dataKey: 'assistData.refreshParam',
            render: (curData, config, {changeFn, changeDataFn}) => {
                const handleClick = () => {
                    changeDataFn('assistData.refreshParam' ,true)
                    setTimeout(() => {
                        changeDataFn('assistData.refreshParam' ,false)
                    }, 1000 * 3)
                }
                return <react.fragment>
                    {
                        config.index === config.parentData.length - 1 &&
                        <popover>
                            <button>{!curData && <icon></icon>}</button>
                        </popover>
                    }
                </react.fragment>
            }
        },
    ]
}

注意: 如果要使用assistData中的数据,其dataKey必须以assistData开头,且必须使用changeDataFn自定义提交assistData数据。

render方法内嵌套组件配置

{
    type: 'container',
    dataKey: 'param',
    render: (curData, config, {changeFn, changeDataFn, JSONForm}) => {
        return <p>
            {
                JSONForm([
                    {
                        type: 'input',
                        dataKey: 'name',
                        placeholder: '请输入param',
                        validate: ['required'],
                    }
                ])
            }
        </p>
    }

这样就可以在container内嵌套组件配置,实现更复杂的表单组件。

JSON表单提交数据

非实时表单提交

非实时表单提交数据,就是在表单输入完毕后,点击提交按钮统一提交所有的数据,其提交的方式如下:

function handleClick() {
    this.FormRefs.getValue((valid, data) => {
        // valid 表示校验结果,false表示校验不通过
    })
}

实时表单提交

实时表单的提交首先需要注册提交函数:

componentDidMount(){
    this.FormRefs.registerSubmit((valid, data) => {
        console.log(valid, data)
    })
}

接着在配置里设置允许实时提交的字段:

{
    formKey: '',
    realTimeSubmit: true
}

如果需要在某些表单组件里自定义是否实时提交,需要在组件配置里设置阻止实时提交字段为true:

{
    dataKey: '',
    preventSubmit: true
}

JSON表单的应用场景

表单分类

a. 按复杂度分类
   1. 简单表单:表单组件为input、select、textarea等常见的几种,且表单组件之间逻辑独立
   2. 复杂表单:表单组件内容和交互复杂且相互之间存在复杂的逻辑
其中复杂表单又可以分为:
   1. 联动表单,上一个表单组件会影响接下来表单的值
   2. 实时表单,表单组件的事件会触发表单的实时提交,例如筛选表单
   3. 富控制表单,表单内部含有很多的控制逻辑

JSON表单最适合的应用场景是简单表单,它可以用极少的代码,快速的构建出表单来,对于复杂类型的表单,JSON表单需要使用container来构建复杂的表单组件、处理复杂的控制逻辑,其代码量优势虽然并不明显,但是JSON表单可以使其代码清晰,将表单组件和表单逻辑彻底解耦,便于抽离和维护,便于共享常用组件,也带来不少的好处。

到目前为止,JSON表单适合大部分的表单应用场景。

JSON表单解决的问题

  1. 减少了表单代码量,不需要重复的开发表单组件,只需要输入组件配置即可

  2. 将表单组件和数据解耦,便于子功能的拆分和常用组件的共享

  3. 简化了校验功能,只需要传入validate字段即可

  4. 添加了自动缓存功能

在我的项目,我尝试了使用原始表单和JSON表单两种方式来实现同一个表单页,原始表单我编写了600多行的代码,而在JSON表单中,只有不到150行。

以上是JSON產生Form表單的詳細解析(程式碼實例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除