这里使用的UI框架是ElementPlus,更换其他组件直接更换constant.ts中的type配置和对应的Form组件即可.
大家可以npm install elementplus_dy_form
来体验。
思路:
1.这里需要使用h函数方便控制要渲染的表单
2.传递type作为组件或html元素进行渲染,
3.默认包一层El-form,每个数组项会包一个El formItem
4.传入formDataKey,对绑定的表单项进行映射
5.通过next函数决定渲染的表单,next函数接收参数即表单数据
建议配置unplugin-auto-impor插件
创建一个静态文件存放配置
import { type DyFormConfig } from '../components/DyForm/DyForm.'
import {ElButton,ElInput,ElCheckbox,ElSelect,ElOption,ElSwitch,ElCheckboxGroup,ElRadioGroup,ElRadio,ElCol,ElDatePicker} from 'element-plus'
export class UserForm {
name?: string
organization?: string
date1?: string
date2?: string
delivery?: boolean
type?: []
resource?: string
desc?: string
personInfo?: string
developerName?: string
sponsorName?: string
}
export function useDyFormConfig(dyForm: any) {
const DyFormConfig: DyFormConfig<UserForm>[] = [
{
type: ElInput,
formItemConfig: {
label: '请输入姓名',
},
formConfig: {
placeholder: '请输入姓名',
},
formDataKey: 'name'
},
{
type: ElSelect,
formItemConfig: {
label: '请选择组织',
},
formConfig: {
placeholder: '请选择您的组织'
},
formDataKey: 'organization',
children: [
{
type: ElOption,
formConfig: { label: '个人', value: 'person' },
},
{
type: ElOption,
formConfig: { label: '公司', value: 'company' }
},
{
type: ElOption,
formConfig: { label: '无', value: 'none' }
}
],
next(formData) {
if (formData.organization === 'none') {
return {
next() {
return {
type: ElInput,
formItemConfig: {
label: '请输入您所属组织'
},
}
}
}
} else if (formData.organization === 'company') {
return [
{
type: 'div',
formConfig: {
style: {
width: '100%',
display: 'flex'
}
},
formItemConfig: {
label: '请选择日期',
},
children: [
{
type: ElCol,
formConfig: {
span: 11
},
children: [
{
needFormItem: true,
type: ElDatePicker,
formDataKey: 'date1',
formConfig: {
type: "date",
placeholder: "请选择进入公司日期",
style: "width: 100%"
},
}
]
},
{
type: ElCol,
formConfig: {
span: 2
},
children: [
{
type: 'span',
children: '-'
}
]
},
{
type: ElCol,
formConfig: {
span: 11
},
children: [
{
needFormItem: true,
type: ElDatePicker,
formDataKey: 'date2',
formConfig: {
type: "date",
placeholder: "请选择毕业日期",
style: "width: 100%"
},
}
]
},
],
next(formData) {
console.log(formData)
return [{
type: ElInput,
formItemConfig: {
label: '请输入个人信息'
},
formConfig: {
placeholder: '请输入个人信息'
}
}]
}
},
]
} else {
return [{
type: ElInput,
formDataKey: 'personInfo',
formItemConfig: {
label: '请输入个人信息'
},
formConfig: {
placeholder: '请输入个人信息'
}
}]
}
}
},
{
type: ElSwitch,
formDataKey: 'delivery',
formItemConfig: {
label: 'Instant delivery',
}
},
{
type: ElCheckboxGroup,
formDataKey: 'type',
formItemConfig: {
label: 'Activity type',
},
children: [
{ type: ElCheckbox, slots: { default: () => '活动1' }, formConfig: { name: 'type', label: '活动1' } },
{ type: ElCheckbox, slots: { default: () => '活动2' }, formConfig: { name: 'type', label: '活动2' } },
{ type: ElCheckbox, slots: { default: () => '活动3' }, formConfig: { name: 'type', label: '活动3' } },
{ type: ElCheckbox, slots: { default: () => '活动4' }, formConfig: { name: 'type', label: '活动4' } }
],
},
{
type: ElRadioGroup,
formDataKey: 'resource',
formItemConfig: {
label: 'Resources'
},
children: [
{
type: ElRadio,
formConfig: {
label: 'Sponsor'
}
},
{
type: ElRadio,
formConfig: {
label: 'Developer'
}
},
],
next(formData) {
const resource = formData.resource
const obj = {
'Sponsor': [
{
type: ElInput,
formDataKey: 'sponsorName',
formItemConfig: {
label: '请输入赞助商名称'
},
}
],
'Developer': [
{
type: ElInput,
formDataKey: 'developerName',
formItemConfig: {
label: '请输入开发商名称'
},
}
],
} as Record<string, DyFormConfig[]>
if (!resource) {
return []
} else {
return obj[resource]
}
},
},
{
type: ElInput,
formConfig: {
type: 'textarea'
},
formDataKey: 'desc',
formItemConfig: {
label: 'Activity form',
}
},
{
type: 'div',
formConfig: {
style: {
width: "100%",
display: "flex"
}
},
children: [
{
type: ElCol,
formConfig: {
span: 6
},
children: [
{
type: ElButton,
formConfig: {
type: 'warning',
onClick: async () => {
const formRef = dyForm!.value!.getFormRef()
formRef.value.validate()
}
},
slots: {
default: () => '确认'
}
}
]
},
{
type: ElCol,
formConfig: {
span: 18
},
children: [
{
type: ElButton,
formConfig: {
type: 'danger',
onClick: () => {
const formRef = dyForm!.value!.getFormRef()
formRef.value.resetFields()
}
},
slots: {
default: () => '取消'
}
}
]
}
]
}
];
return {
DyFormConfig
}
}
使用示例
<script setup lang="ts">
import {DyForm} from './components/Dyform/DyForm.ts';
import { useDyFormConfig, UserForm } from './utils/constant'
import {ref,reactive} from 'vue'
const dyForm = ref(null)
const { DyFormConfig } = useDyFormConfig(dyForm)
const form = ref<UserForm>({
name: '',
organization: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
personInfo:''
});
const rules = {
name: [
{ required: true, message: 'Please input Activity name', trigger: 'blur' },
{ min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' },
],
region: [
{
required: true,
message: 'Please select Activity zone',
trigger: 'change',
},
],
delivery: [
{
required: true,
message: 'Please select delivery',
trigger: 'change',
},
],
organization: [
{
required: true,
message: 'Please select organization',
trigger: 'change',
},
],
date1: [
{
type: 'date',
required: true,
message: 'Please pick a date',
trigger: 'change',
},
],
date2: [
{
type: 'date',
required: true,
message: 'Please pick a time',
trigger: 'change',
},
],
type: [
{
type: 'array',
required: true,
message: 'Please select at least one activity type',
trigger: 'change',
},
],
resource: [
{
required: true,
message: 'Please select activity resource',
trigger: 'change',
},
],
desc: [
{ required: true, message: 'Please input activity form', trigger: 'blur' },
],
}
const formConfig = reactive({
labelWidth: '130px',
rules
})
</script>
<template>
<DyForm ref="dyForm" v-model="form" :dyFormConfig="DyFormConfig" :formConfig="formConfig" />
</template>
<style scoped>
#app,
html,
body {
width: 100vw;
height: 100vh;
}
</style>
结果展示:
表单数据精准绑定嵌套的复杂数据类型
下面数据中,如果我想更新form.info.address
,组件支持吗?Yes
const form = ref<UserForm>({
name: '',
organization: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
personInfo:'',
info:{
address: "",
job:""
}
});
只需要配置formKey
// ...
{
type: ElInput,
formConfig: {
type: 'textarea'
},
formDataKey: 'info.address', 这样配置就行了
formItemConfig: {
label: '住址',
}
},
// ...
示例二
我们想精准绑定test.user[0].age
该怎么做?
非常简单,如下图所示配置即可。
看结果展示
注意
不是很建议表单嵌套十分复杂的数据类型,如果有这种需求建议打平,然后自己再组装,如果不追求性能忽略这条。