一、前沿
基于 Ant Design Vue 组件库实现了表单的配置化生成,通过 schema 配置化的方式实现表单的动态渲染、数据绑定和更新等功能,而提交按钮及获取数据逻辑由使用方自行提供。通过 schema
对象来定义表单的结构和属性,modelData
对象存储表单数据。主要组件包括 z-form-generator
、formGeneratorGroup
以及各种具体的表单字段组件(如 field-date
、field-radio
等)。
二、具体实现
1. schema
配置
- 结构定义:
schema
对象包含containers
(表单结构的 JSON 数据)、colNum
(最多展示列数)和isViewType
(表单是否为只读)等属性。containers
中可以包含多个组件配置,每个组件配置又有type
、label
、model
等属性。
schema: {
containers: [],
colNum: 2,
isViewType: false
}
- 字段配置:不同类型的字段组件(如日期、单选、多选等)根据
schema
中的type
属性来确定使用哪个具体的组件进行渲染。例如,type: 'date'
会使用field-date
组件。
2. 组件渲染
formGeneratorGroup
组件:根据schema
中的type
属性动态渲染不同的表单字段组件。通过getFieldType
方法type
获取组件名称,并使用 JSX 进行渲染。
// formGeneratorGroup.js
const { getFieldType, field, colNum } = this
const comArr = ['area', 'checkbox', 'date', 'file', 'input', 'radio', 'search', 'select', 'upload', 'modal', 'cascader', 'list']
let isCom = _.includes(comArr, field.type)
const component = isCom ? getFieldType(field) : null
const { type, ...restProps } = field
return (
<a-col>
{
component && <component
schema={restProps}
modelData={this.modelData}
isViewType={this.isViewType}
on-model-updated={this.onModelUpdated}
on-error-updated={this.onErrorUpdated}
on-schema-updated={this.onSchemaUpdated}
/>
}
</a-col>
)
- 具体字段组件:每个字段组件(如
field-date
、field-radio
等)根据schema
中的属性进行渲染,并处理相应的事件(如onChange
)。
getFieldType ({ type } = {}) {
if (!type) {
throw new Error('请确认组件类型')
}
return `Field-${type}`
},
3. 组件化设计
采用组件化的设计思想,将不同类型的表单组件封装成独立的组件,如 FieldRadio
、FieldCheckbox
、FieldFile
等。每个组件都接收 schema
和 modelData
作为 props
,通过 render
函数动态渲染表单元素。
// field-radio.vue
export default {
name: 'FieldRadio',
props: {
schema: {
type: Object,
default: () => ({}),
require: true,
},
modelData: {
type: Object,
default: () => ({}),
},
},
methods: {
changeHandle (e) {
this.value = e.target.value
},
},
render () {
const { label, model, list, optionName, ...restSchema } = this.schema
const { keyName: key, valueName: val } = {
keyName: 'key',
valueName: 'val',
...optionName,
}
return <a-form-model-item
label={label}
prop={model}
>
<a-radio-group
value={this.value}
prop={{ ...restSchema }}
onChange={this.changeHandle}
>
<a-row>
{
list && list.map(el =>
<a-col span={12}>
<a-radio value={el[key]}>
{el[val]}
</a-radio>
</a-col>
)
}
</a-row>
</a-radio-group>
</a-form-model-item>
},
}
4. 数据绑定与更新
通过 modelData
对象实现表单数据的绑定。在组件中,通过 props
属性将 model
绑定到表单元素上,然后通过 $emit
触发自定义事件,将数据更新传递给父组件。
// field-radio.vue
methods: {
changeHandle (e) {
this.value = e.target.value
this.$emit('model-updated', this.schema, this.value)
},
}
5. 校验规则初始化
通过 initRules
方法初始化表单的校验规则。根据 schema
中的 required
属性和组件类型,为每个字段添加相应的校验规则。
// formGenerator.vue
initRules () {
const { containers, rules } = this.cloneSchema
// 初始化规则校验对象
let initRules = { ...rules }
// 平铺所有容器的fields
const components = containers.reduce((acc, container) => {
acc.push(...container.components);
return acc;
}, []);
// 统一处理字段规则
components.forEach(field => {
const { code, type, required, inputType, regular, errorMessage, precision } = field;
// 初始化当前字段的校验规则
if (!initRules[code]) initRules[code] = [];
// 兼容 required 历史数据
if (required) {
const requiredRule = type === 'list'
? { required: true, message: '该列表不得为空,请为列表新增数据' }
: { required: true, message: '该项不得为空', trigger: type === 'date' ? 'change' : 'blur' };
initRules[code].unshift(requiredRule);
}
// 如果是input类型组件,处理其校验规则
if (type === 'input') {
let ruleItem = initRules[code];
// 处理内建的输入框类型校验
if (inputType && ['phone', 'intNum', 'number', 'email', 'idCardNo', 'bussNo', 'bankNo'].includes(inputType)) {
const { reg, message } = inputType === 'number' ? RulesReg[inputType][idx] : RulesReg[inputType]
addValidationRule.call(this, ruleItem, reg, message)
}
// 处理自定义正则校验
if (regular) {
const reg = new RegExp(regular);
const message = errorMessage;
addValidationRule.call(this, ruleItem, reg, message)
}
initRules[code] = [...ruleItem];
}
})
// 更新规则
this.rules = initRules;
}
addValidationRule(ruleItem, reg, message) {
ruleItem.push({
validator: (rule, value, cb) => this.valitaRule(reg, value, cb, message),
trigger: 'blur',
});
}
三、特点
- 配置化设计:通过
schema
配置化的方式,实现了表单的动态生成和定制,提高了代码的可维护性和可扩展性。 - 组件化开发:将不同类型的表单组件封装成独立的组件(如
field-date
、field-radio
等),提高了代码的复用性和可测试性。 - 动态渲染:根据
schema
中的type
属性动态渲染不同的表单组件,实现了表单的灵活定制。 - 规则校验:支持多种类型的规则校验,包括必填项校验、输入框校验等,确保了用户输入数据的合法性。