前言
因为在项目中经常需要对搜索或者添加编辑等业务去表单的联动效果,我之前封装的思路是用useMode
去实现表单的联动,但是联动的效果比较多的话if判断的语句就比较恶心,采用链表和hooks
的思想就会让代码看着简洁以及好维护一点
实现代码
创建一个实现链表的函数:
/***
* @param {string} type - 类型
* @param {Object} payload - 组件使用到的参数
* @param {Function} next - 获取下一项
* @param {Object} parent - 上一项
* @returns {Object} 返回formitem
*/
export const createFormItem = (type, payload, next, parent) => {
if (!next) {
next = () => null
}
if (!parent) {
parent = null
}
const nextFunc = (current, acients) => {
const nextItem = next(current, acients)
if (!nextItem) {
return null
}
nextItem.parent = current
return nextItem
}
return {
type,
payload,
next: nextFunc,
parent
}
}
hooks中的代码:
import { useEffect, useState } from "react"
import {createFormItem } from "@/util/index"
class User {
name: string = ""
pass:string = ""
}
const addUser = () => {
const [formData, setFormData] = useState(new User())
/**
* input 代表是要创建的类型
* {label:表单显示的label,name:表单的字段,value:表单绑定的value(一定要是动态的)}
* (current) => (current.value=="123"?item2:null) // 联动的判断 如果当前项的value是123 name就会返回item2这一项 如果不是123 name就会是null啥都没有
*/
const item1 = createFormItem('input', { label: '用户名', name: 'name', value: formData.name }, (current) => (current.value=='123'?item2:item3))
const item2 = createFormItem('input', { label: '密码', name: 'pass', value: formData.pass, },(current) => (item3))
const item3 = createFormItem('input', { label: '年龄', name: 'age', value: formData.age }, (current) => (current.value == '123' ? item4 : null))
const item4 = createFormItem('input', { label: '性别', name: 'sex', value: formData.sex })
/**
* 有多少项你就创建多少项只需要维护next函数就可以了
*/
return {
root:item1,
formData,
setFormData
}
}
export default addUser
父组件中代码:
import { useEffect, useState } from "react";
import { useModel } from "umi";
import MyForm from "@/components/myForm";
export default function HomePage() {
const userConfig =useModel("user")
return (
<div>
<MyForm {...userConfig} />
</div>
);
}
子组件的代码:
import { Form, Input } from 'antd'
import {useModel } from "umi"
import { memo, useState } from 'react'
const initFormItem = (res) => {
if (!res) {
return null
}
switch (res.type) {
case 'input': return inputFormItem(res.payload, res.next)
default: return null
}
}
const inputFormItem = (config, next) => {
const c = next(config)
return (<>
<Form.Item label={config.label} name={ config.name}>
<Input style={{ width: 200,height:50 }}></Input>
</Form.Item>
{ initFormItem(c)}
</>
)
}
const MyForm = (props) => {
const { formConfig = {}, formData = {}, setFormData = () => { }, root = {} } = props
const onValuesChange = (value,allvalue) => {
setFormData({...formData,...allvalue})
}
return (
<>
<Form className="dark_form" autoComplete="off" onValuesChange={ onValuesChange} {...formConfig} >
{ initFormItem(root)}
</Form>
</>
)
}
export default memo(MyForm)
封装的组件代码:
import { Form, Input } from 'antd'
import {useModel } from "umi"
import { memo, useState } from 'react'
const getNext = (res) => {
let current = res
let acients = [] // 存取所有项
acients.unshift(current)
while ((current = current.parent)) {
acients.unshift(current)
}
return res.next(res.payload, acients)
}
const initFormItem = (res) => {
if (!res) {
return null
}
switch (res.type) {
case 'input': return inputFormItem(res)
default: return null
}
}
const inputFormItem = (res) => {
return (<>
<Form.Item label={res.payload.label} name={ res.payload.name}>
<Input style={{ width: 200,height:50 }}></Input>
</Form.Item>
{ initFormItem(getNext(res))}
</>
)
}
const MyForm = (props) => {
const { formConfig = {}, formData = {}, setFormData = () => { }, root = {} } = props
const onValuesChange = (value, allvalue) => {
setFormData({...formData,...allvalue})
}
return (
<>
<Form className="dark_form" autoComplete="off" onValuesChange={ onValuesChange} {...formConfig} >
{ initFormItem(root)}
</Form>
</>
)
}
export default memo(MyForm)