「功能实现」越折腾越有趣,封装了一个表单组件

3,704 阅读6分钟

我在封装详情页功能的时候,其实最早的雄心壮志是做低代码平台。看了几篇文章,再看看自己的小键盘以及手里的项目排期,就放弃了。我和我的梦想终究是隔着时间、人力、能力等多重重险阻。

但是,我转念一想,如果把前端的功能简化,不就有时间做低代码平台的开发了吗?对于自己的机智,反手就是一个赞。

于是开始计划,最大化的模块化和组件化前端功能,这样一来,每次新需求开发就会非常的便捷。而后台系统,最复杂也最啰嗦的就是表单功能,所以我准备将表单做成组件化的。

表单功能不用再重复的码一些个输入框、下拉项、日期控件等代码,是不是节省了很多时间,节省出来的时间又可以去研究低代码开发,是不是离财富自由更近了一步。(✧◡✧)

基于React框架开发,使用的antd UI组件库。

整体设计

功能介绍

antd提供的Form表单控件,已经集成了数据录入、校验以及对应样式等。但是我们实际开发的时候,后台系统的添加、编辑、其他数据录入等表单弹窗,内容项大多是Input、Radio、CheckBox等,每次开发都重复码一些代码。所以我根据日常开发经验,将常规的表单项做了进一步的封装处理。

封装处理之后,只需将表单项类型、key值等关键变量放到一个数组对象中,通过props传递到表单组件中即可。

当表单填写完成之后,填写的数据会通过callback函数回传到表单弹窗中。

参数介绍

参数说明类型默认值
data表单默认数据object{}
list表单项展示数组any[][]
layout表单布局object-
callback提交操作的回调函数(value,list) => void
getFormRef获取formRef方法(formRef) => void

表单项类型

目前支持的表单项类型如下,未来如果有新的开发思路,会继续增加

类型key
输入框input
数值型输入框inputNumber
日期date
下拉选择器select
多选框checkbox
单选框radio
文本域textArea
纯文本展示text

细节处理

细节处理只放关键代码,完整代码已经放到github上了,github地址在文末。下面主要将设计思路和实现方式

类型区分

list数组,根据每个元素的fieldtype区分不同的展示内容。

{
  list.map((formItem, formIndex) => {
    return (
      <Fragment key={formIndex}>
        {formItem.fieldtype === 'input' && inputContent(formItem)}
        {formItem.fieldtype === 'inputNumber' && inputNumberContent(formItem)}
        ......
      </Fragment>
    );
  });
}

input

  • 输入框使用的antd提供的Input组件。
  • 如果输入框类型的内容项,展示内容不单单是输入框,可能还包含其他的比如提示文案,可以使用children进行内容替换。
/**
 * 输入框类型
 * @param {object} item 表单项
 */
const inputContent = item => {
  return (
    <>
      {item.children ? (
        item.children
      ) : (
        <Form.Item label={item.label} name={item.key} rules={item.rules} disabled={item.disabled}>
          <Input placeholder={`请输入${item.label}`} />
        </Form.Item>
      )}
    </>
  );
};

inputNumber

  • 输入框使用的antd提供的InputNumber组件。
  • 数字类型的输入框的特别之处在于输入的数值可以设置最小值和最大值、小数点、每次可以改变的步数。这些都可以通过设置对应的属性进行控制。
  • 数字类型的输入框支持展示单位,通过unit变量控制单位的展示。
<Form.Item label={item.label} className={classnames({ required: item.required })}>
  <Form.Item noStyle name={item.key} rules={item.rules} disabled={item.disabled}>
    <InputNumber style={{ width: '50%' }} step={item.step} min={item.min} max={item.max} precision={item.precision} />
  </Form.Item>
  {item.unit && <span style={{ marginLeft: '10px' }}>{item.unit}</span>}
</Form.Item>

date

  • 日期类型使用的antd提供的DatePicker组件。
  • 日期类型支持不同的时间展示方式,通过format变量实现。
  • 日期类型可以设置可选时间范围,可选范围包括起日和止日,也可单独设置起日或止日。
  • 写文档的时候突然意识到,实际日期类型也可以支持日期精确到年或是月或是日,目前组件没有实现这个功能,后续实现之后再更新文档。(灵感就是这么一瞬间就来了)

select

  • 下拉选择器类型使用的antd提供的Select组件。
  • 下拉选择器操作一般获取的是value,如果需要拿到选中的节点文本 label,通过onChange时间设置option变量的值为选择的下拉项的值。
  • 有一种特殊情况,当下拉项选择其他时,需要输入其他选项的具体值,所以增加了可输入其他的文本域功能。
{/* 下拉项中有需要文本输入的情况 */}
{item.textArea.code && item.option.value === item.textArea.code ? textAreaContent(item.textArea) : null}

checkbox

  • 多选框类型使用的antd提供的Checkbox组件。

radio

  • 单选框类型使用的antd提供的Radio组件。
  • 有一种特殊情况,当单选项选择否或拒绝时,需要输入原因或者说明,所以增加了可输入其他的文本域功能。

textArea

  • 文本域类型使用的antd提供的Input.TextArea组件。
  • 当文本域类型表单项和其他表单项组合展示时,展示的布局值需要和组合的表单项一致,所以根据type类型做了特殊处理。
let areaLayout = {};
if (type === 'other') {
  areaLayout = { wrapperCol: { offset: layout.labelCol, span: layout.wrapperCol } };
  label = null;
}

text

纯展示类型,展示具体内容即可。

如何使用

引入组件

  • 一般公共组件会放在components。完整的代码已经放github上了,github地址在文末。,这里不在重复,主要将一下实现思路。
  • data,基础数据对象,里面放一些表单初始化的数据,比如编辑的时候,表单需要回显之前填过的数据,所以我把这部分数据放到了data里面。
  • list,这个是重点,它是一个数组对象,放完整的表单数据,所有需要展示的表单项都要放到list数组中,
  • callback,是一个回调函数,提交表单时,需要请求后端提供的接口进行数据上报。callback函数中的参数value包含所有表单项的操作值。
  • getFormRef,是一个操作函数,有一些弹窗的操作按钮需要特殊处理,不是通过From组件上的onFinish方法进行的操作,所以需要将formRef返回到弹窗中,获取实际的操作。
import BaseFormUI from '@/components/BaseFormUI';

......

const config = {
  data: {
    ...data,
    initFieldsValueFlag: true,
  },
  list: list,
  getFormRef: getFormRef,
  callback: callback,
};

......
<BaseFormUI {...config} />

弹窗展示

数据提交

如果后端接口没有特殊要求,value对象中的数据基本就满足了,如果需要其他值可以从list中获取。

总结

github地址: react-antd-manage

功能完成之后,发现没有自己最开始设想的那么复杂。当然了,也跟功能的兼容程度有关系,不适用特别复杂的表单,比如表格类的表单。

未来希望伴随着学习和进步,进一步完善表单组件。

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿