经常开发管理系统的小伙伴们肯定或多或少都遇到过表单需求,对于一个系统而言,动辄就是十几,几十个表单;如果每个表单都按照传统模式编写的话,简直要把前端累死,看着一段段大同小异的代码,也是提不上一点劲,甚至看着这些它懂你,你不想懂它
的代码就犯恶心。
本着偷懒的精神,我就想能否封装一个动态表单,实现思路大致就是通过JSON配置,动态生成表单页面
,于是说干就干,咱玩的就是真实对吧。开撸,开撸.....
type TreeItem = {
value: string
label: string
children?: TreeItem[]
}
export type FormListItem = {
// 栅格占据的列数
colSpan?: number
// 表单元素特有的属性
props?: {
placeholder?: string
defaultValue?: unknown // 绑定的默认值
clearable?: boolean
disabled?: boolean | ((data: { [key: string]: any }) => boolean)
size?: 'large' | 'default' | 'small'
group?: unknown // 父级特有属性,针对嵌套组件 Select、Checkbox、Radio
child?: unknown // 子级特有属性,针对嵌套组件 Select、Checkbox、Radio
[key: string]: unknown
}
// 表单元素特有的插槽
slots?: {
name: string
content: unknown
}[]
// 组件类型
typeName?: 'input' | 'select' | 'date-picker' | 'time-picker' | 'switch' | 'checkbox' | 'checkbox-group' | 'checkbox-button' | 'radio-group' | 'radio-button' | 'input-number' | 'tree-select' | 'upload' | 'slider'
// 表单元素特有的样式
styles?: {
[key: string]: number | string
}
// select options 替换字段
replaceField?: { value: string; label: string }
// 列表项
options?: {
value?: string | number | boolean | object
label?: string | number
disabled?: ((data: { [key: string]: any }) => boolean) | boolean
[key: string]: unknown
}[]
// <el-form-item> 独有属性,同 FormItem Attributes
formItem: Partial<FormItemProps & { class: string }>
// 嵌套<el-form-item>
children?: FormListItem[]
// 树形选择器数据
treeData?: TreeItem[] // 只针对 'tree-select'组件
// 组件显示条件
isShow?: ((data: { [key: string]: any }) => boolean) | boolean
}
export type FConfig = {
form: Partial<InstanceType<typeof ElForm>> // Form Attributes 与Element属性一致
configs: FormListItem[] // 表单主体配置
}
1.实现思路,提供一个isShow
方法,将方法绑定在对应的组件上,从而组件显示隐藏条件
isShow: (data = {}) => {
return model.value.region == 'shanghai'
}
....
<el-form-item v-if="isShow(model)" v-bind="item.formItem">
2.目标组件是否禁用,需要根据某个组件是否有值来判断
- disabled: (data = {}) => {
- return !model.value.date1
}
....
<component :disabled="disabled(model)"></component>
3. 表单验证
formItem: {
prop: 'name',
label: 'Activity name',
rules: [
{
required: true,
message: 'Please enter content',
trigger: 'blur'
}
]
}