基于React的表单开发的分析(上)

4,263 阅读4分钟

本文主要讲解后台系统与表单相关的页面开发,并分析如何才能更好地、高效地开发。

技术栈

  • React
  • Antd

背景

Antd

以下我都将Ant Design 简称为 Antd

Ant Design是个服务于企业级产品的UI框架,主要可以用于中后台系统,它有基于React、Vue和Angular的实现。个人感觉Antd还是很强大的,API相当完善、全面,基本能实现你想要的各种功能。

表单
在开发普通的后台系统时,开发得最多的就是实体的 新建、编辑和详情页面,这三个页面有共通之处,也有不同之处,感觉有可以复用的地方,但是有些地方又需要特殊处理。

表单页如图:

详情页如图:

新建、编辑、详情页与Form表单组件的关系

从上面的几个图中我们看出:

  • 新建和编辑可以复用一个Form组件
  • 新建时不传给Form组件数据
  • 编辑时会请求后端实体的数据,传给Form组件,进行数据初始化
  • 详情页照理说也可以用Form组件,但是,UI视图上面Form组件和详情页面会不一致,比如:详情页只是纯粹展示的div,而非各种表单控件了。

思考并进行实现

通过上面的调研,我们可以考虑把详情页、新建和编辑做成单独的页面,但是新建和编辑复用同一个Form组件,Form组件进行数据收集、展示、表单校验,额外的逻辑处理(比如新建、编辑的提交动作、跳转页面和数据过滤)可能会有不同,所以在新建、编辑页面进行分别的处理。
ok,我们看看Form表单代码实现: 更多详情看这里

      <Form onSubmit={this.handleSubmit}>
        <FormItem
          {...formItemLayout}
          label="E-mail"
        >
          {getFieldDecorator('email', {
            rules: [{
              type: 'email', message: 'The input is not valid E-mail!',
            }, {
              required: true, message: 'Please input your E-mail!',
            }],
          })(
            <Input />
          )}
        </FormItem>
        <FormItem
          {...formItemLayout}
          label="Password"
        >
          {getFieldDecorator('password', {
            rules: [{
              required: true, message: 'Please input your password!',
            }, {
              validator: this.validateToNextPassword,
            }],
          })(
            <Input type="password" />
          )}
        </FormItem>
...

上面的代码是利用Antd表单实现的,这里会有一些问题:

  • 平均一个表单控件用平均12~17行代码(不包含复杂逻辑和回调函数),在大型系统中,一个复杂的表单可能会有30~40个控件,怎么办? 写一个2000+行的Form.js文件吗?
  • 如下写法,会出现冗余代码:

每个控件都要写FormItemgetFieldDecorator ,会出现多次,而且格式一致

        <FormItem
          {...formItemLayout}
          label="E-mail"
        >
          {getFieldDecorator('email', {
            rules: [{
              type: 'email', message: 'The input is not valid E-mail!',
            }, {
              required: true, message: 'Please input your E-mail!',
            }],
          })(
            <Input />
          )}
        </FormItem>
  • 详情页需要重写一套完全不一样的逻辑和UI,无法复用Form组件中的逻辑
  • 如果有动态标签怎么办? 比如我遇到一个场景:页面中有一些字段是前端写死的,比如 用户名,密码等,还有一些字段,是用户上传一个模板文件,后端解析模板并返回给前端的,结构可能是这样:
{
    "name":"标签名1",
    "type":1, // 1:文本框, 2:百分比,3:数字,4:金额,5:单选按钮,6:单选下拉框,7:多选按钮,8:多选下拉框,9:日期-单日,10:日期-区间
    "commonUse":true, //是否常用标签
    "requiredTag":true, //是否必填
    "placeholder":"这个是描述",
    "option":[ //选择项会用到此字段
        {
            "id":1,
            "name":"名字",
            "defaultOption":true, // 是否默认选中
        }
    ]
}

更好的解决方案

  • 为了避免一个Form超过1000行这种情况出现,我们应该把大型Form表单进行拆分

如下图,有个合同的Form表单,我们按照类型做如下拆分:

  • 针对上面的其余问题,我们计划提取出这样一个公共组件:
    • 组件接收:需要渲染表单的字段、初始数据、字段的控件类型等
    • 能根据字段的不同的控件类型渲染不同的表单控件
      • Select
      • Input
      • ...
    • 详情页也能复用这个组件
    • 具有可扩展性(比如Antd的API的方法在此组件中均能使用)

总结

后台系统中我们开发的大部分页面都是表单页(新建、编辑、详情),少部分是列表页,我们应该多考虑路由划分、数据层设计、业务组件拆分、公用组件设计与实现,如果这些方面做好了,积累一定的经验,以后开发后台系统一定会事半功倍。
Tip: 我准备在下期再详细讲解上面提到的表单公用组件的设计与实现。
下一期: => 基于React的表单开发的分析(下)

相关链接

ant.design/components/…