Heim >Web-Frontend >js-Tutorial >Detaillierte Analyse des von JSON generierten Formulars (Codebeispiel)

Detaillierte Analyse des von JSON generierten Formulars (Codebeispiel)

不言
不言nach vorne
2018-11-20 14:47:225741Durchsuche

Dieser Artikel bietet Ihnen eine detaillierte Analyse (Codebeispiel) des von JSON generierten Formulars. Ich hoffe, dass er Ihnen als Referenz dienen wird.

JSON-Formular

Beschreibung

JSON-Formular ist eine abstrakte Komponente, die auf React basiert und im JSON-Datenformat beschriebene Formulare konvertieren kann kann mit nur wenigen Codezeilen schnell Formulare generieren.
Die Vorteile von JSON-Formularen sind:

  1. Sie können schnell ein Formular erstellen

  2. Die Daten, Logik und Ansichten des Formulars sind zur einfachen Extraktion getrennt.

  3. Bietet zusätzliche Funktionen wie Verifizierung und automatisches Caching, um das Eingabeerlebnis zu verbessern

  4. Kann komplexe Inhalte teilen Formularkomponenten projektübergreifend

Nachteile des ursprünglichen Formulars

1: Riesige Menge an Code und geringe Entwicklungseffizienz
Jedes Mal, wenn Sie eine Formularseite entwickeln, benötigen Sie Das wiederholte Schreiben der Formularkomponenten und des Codes für seine interaktiven Ereignisse hat nichts mit der Hauptgeschäftslogik zu tun. Darüber hinaus erfordern auch zusätzliche Funktionen wie Formularüberprüfung und Caching viel Code, was zu einem Formularseite mit Code.

2: Es ist nicht einfach, es zu trennen und weiter zu abstrahieren.
Auf einer Formularseite werden Formulardaten, Formularkomponenten und Steuerlogik häufig miteinander vermischt, wenn festgestellt wird, dass es sich um eine bestimmte Unterfunktion handelt Wird in vielen Szenarien verwendet. Wenn sie alle verwendet werden müssen, ist es nicht einfach, die Unterfunktion herauszutrennen. Da die Logik, die Daten und die Ansichten gemischt sind, ist eine sorgfältige Prüfung erforderlich, um die Unterfunktion zu entfernen, ohne dass dies beeinträchtigt wird führt zum Ausfall der Funktion.

3: Hohe Wartungskosten
Das ist auch meine persönliche Erfahrung Eine kleine Funktion im Projekt Damals stellte ich fest, dass nicht nur die bisherige Logik geändert wurde, sondern auch viele Fehler eingeführt wurden, was die Wartung zu einer risikoreichen Aufgabe in einer Form mit sehr komplexer Logik machte.

4: Zusätzliche Verarbeitung von Funktionen wie Überprüfung und Caching ist erforderlich

Eine Kastanie

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>

Das Obige ist ein Formular, das aus drei häufig verwendeten Formularkomponenten besteht, die in JSON beschrieben werden. Das Rendering ist wie folgt:

Detaillierte Analyse des von JSON generierten Formulars (Codebeispiel)

Format des JSON-Formulars

{
    formKey: 'paramAddForm',
    data: {},
    config: []
}
属性 是否必传 说明 类型 默认值
formKey 用来自动缓存,localStorage的key,不传表示不自动缓存 string -
className 用来添加一些自定义样式 string -
data 表单的提交数据,有自动缓存和校验功能 object -
assisData 用于表单控制逻辑的额外数据 object -
config 组件配置,表单组件的配置 Array -
realTimeSubmit 表单是否实时提交,一般用于筛选表单 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的字段,里面是每一项里面的表单组件配置的集合,其表单组件的效果如下图所示:

Detaillierte Analyse des von JSON generierten Formulars (Codebeispiel)

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行。

Das obige ist der detaillierte Inhalt vonDetaillierte Analyse des von JSON generierten Formulars (Codebeispiel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen