- 作者:老汪软件技巧
- 发表时间:2024-09-15 21:02
- 浏览量:
背景
最近看一个项目,发现了一种相当优雅的表单实现方式。其实本质上并不复杂,就是多了一些封装,让我们写的更好看一些。
实现一
笔者之前自己写表单都是直接去 Form.Item 一个个堆积起来的,比如这样去实现
<Form>
<Form.Item>
item1
Form.Item>
<Form.Item>
item2
Form.Item>
<Form.Item>
item3
Form.Item>
<Form.Item>
item4
Form.Item>
Form>
一个一个堆积起来实现其实也挺清晰的,但是如果Form.Item数量一多的话,整个代码的长度就会很长,实际去维护迭代的时候也需要去找找那部分代码具体写在哪里了,维护起来会比较费劲。
实现二
还有一种写法,会在表单数据量比较大的情况表现的更好。这种写法把我们展示表单的这个操作分成了三个模块
第一个模块是 JS 的数据,来代表我们想要渲染的表单第二个部分是一个函数,用于生成表单项第三个部分是通过 map 返回表单组件的JSX结构
// 定义一个表单字段数组,每个字段包含标签、字段名、子组件和验证规则
const baseInfo: DEMS.FormField[] = [
{
label: 'x1', // 表单项的标签
field: 'x1', // 表单项的字段名,用于表单数据的键
children: <Input />, // 表单项的子组件,这里是一个输入框
rules: [{ required: true, message: 'x1不能为空' }], // 验证规则,要求该字段必填
},
{
label: 'x2', // 表单项的标签
field: 'x2', // 表单项的字段名
children: <Input />, // 表单项的子组件,这里是一个输入框
// 没有定义验证规则,表示该字段不是必填项
},
{
label: 'x3', // 表单项的标签
field: 'x3', // 表单项的字段名
children: <InputTag saveOnBlur placeholder='xxx' allowClear />, // 表单项的子组件,这里是一个标签输入框
// 没有定义验证规则
},
];
// 定义一个函数,用于生成表单项
const formItem = ({ span, field, ...rest }: DEMS.FormField) => {
// 返回一个包含表单项的列组件,列的宽度由span决定,如果未指定则使用全局默认值
return (
<Col span={span || Number(globalSpan)} key={String(field)}>
<Form.Item field={field} {...rest} /> // 使用Form.Item组件来定义表单项,并传入字段名和其他属性
Col>
);
};
// 返回表单组件的JSX结构
return (
<div className='layout-card'> {/* 包裹表单的容器 */}
<div className='layout-content'> {/* 表单内容的容器 */}
<Form layout='vertical' form={form}> {/* 定义一个垂直布局的表单 */}
<Row gutter={gutter}>{baseInfo.map(formItem)}Row> {/* 使用Row组件来包裹所有的表单项,并设置间距 */}
{/* 遍历baseInfo数组,为每个字段调用formItem函数生成表单项 */}
Form>
div>
div>
);
这份代码好在哪里呢?
他通过将字段定义和表单项生成分离,使得“数据”和“展示数据”变成了两个模块,数据变成了一个 js 的信息,而展示数据这个动作,变成了一个处理数据变成 JSX 的函数。baseInfo.map(formItem): 这行代码遍历baseInfo数组,并为每个字段调用formItem函数,生成表单项。这种写法非常清爽,写起来很好看。如果说不只有 baseInfo 这一个 JS 对象,而是有多个的情况下,formItem函数就可以被重用,用于生成不同的表单项。
那么这就是本篇文章的全部内容~