Skip to content

表单配置化生成方案

pengzhanbo

934字约3分钟

development

2022-03-17

一个简单的基于 vue3 的表单配置化生成方案,可以作为思路参考。

前言

本方案是个人在做某个项目时,需要实现一个简单的表单配置化生成,而做的一个方案。 最终结果是通过一份表单配置,渲染为一个表单,并支持:

  • 支持多种表单字段类型 (单行文本/多行文本/数字/下拉/多选/单选 等),并支持嵌套字段(对象/数组)
  • 支持字段校验
  • 支持条件判断显示/隐藏 表单字段
  • 支持字段分组展示

提示

完整代码仓库地址: formative

效果展示

通过配置生成表单:demo 1

配置的字段为对象或者数组时:demo 2

对配置的字段进行分组展示:demo 3

方案说明

通过配置生成表单,需要明确如何实现 表单字段 与对应的表单组件进行关联,并实现数据绑定

协议配置

约定一个协议,通过一个对象来表示 表单中某一个字段:

FieldSchema:

{
  "type": "表示字段的类型,比如单选、多选、单行文本、多行文本等",
  "field": "表示字段的名",
  "label": "表示字段显示的标签",
  "default": "字段默认值",
  "description": "字段描述信息,作为提示信息使用"
}

对于完整的表单,则使用 FieldSchema[] 的数组形式进行配置。

表单字段与组件关联

在 vue 中, 组件可以通过 h(component, attrs[, children]) 渲染函数 进行渲染, 通过 h() 函数,可以实现动态渲染不同的组件。

我们可以利用这一特性,首先 字段类型与对应的组件进行映射,通过映射关系,用 字段类型获取对应的组件, 然后调用 h() 进行渲染。

// 字段类型 与 组件 映射
const componentMap = {
  radio: RadioField,
  checkbox: CheckboxField,
  text: TextField,
  select: SelectField,
}
{
  name: 'Field',
  props: ['fieldType'],
  setup(props) {
    return () => h(componentMap[props.fieldType])
  }
}

表单数据绑定

对于表单数据,需要实现 数据初始化,以及 对应的 Field组件对数据的可读写。

在vue中,我们可以使用 provide/inject API, 在 表单组件的根组件,通过 provide() 进行注入,在内部的 FieldComponent 中通过 inject() 获取对应的数据,进行读写。

/**
 * 通过 provide 输入数据
 */
const useFormDataProvide = (formData: FormData): FormInjectKey => {
  const key: FormInjectKey = Symbol('formData')
  provide(key, formData)

  return key
}

/**
 * 通过 inject 获取数据
 */
const useFormData = (key: FormInjectKey): FormData => inject<FormData>(key)!

由于需要支持 字段为对象/数组时产生的 多层级数据结构,还需要考虑 FieldComponentFormData.a.b 的 深层数据的读写。

可以通过实现 dotPath, 通过 FormData['a.b'] 的形式来读写 FormData.a.b,这样 FieldComponent 只需要知道 a.bdotPath 字段路径即可配合 inject() 获取的表单数据进行读写。

const useDotPath = <T = any>(model: FormData, dotKey: ComputedRef<string>) => {
  const binding = computed<T>({
    set(data) {
      setDotPath(model.value, dotKey.value, data)
    },
    get() {
      return getDotPath(model.value, dotKey.value)
    },
  })

  return binding
}

技术实现

formative 仓库中, 通过本方案实现了一个 配置化生成表单的库。

  • src/components/Formative.tsx 文件作为表单根组件。
  • src/components/Field.tsx 文件作为根据表单字段动态选择对应组件进行表单字段渲染。
  • src/components/Group.tsx 文件实现了对表单字段进行分组。
  • src/components/[other].tsx 其他文件实现了 各种表单字段组件。

有兴趣了解细节的,可以阅读 formative 源码, 我在关键位置进行了相关的代码注释说明。

同时,你可以直接拉取 源码,在本地进行运行。并授权代码使用。