• 作者:老汪软件技巧
  • 发表时间: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函数就可以被重用,用于生成不同的表单项。

那么这就是本篇文章的全部内容~