Bootstrap

Vue3+Ts+Elementpuls--动态表单(根据配置项,动态生成表单)

这里使用的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该怎么做?
在这里插入图片描述
非常简单,如下图所示配置即可。
在这里插入图片描述
看结果展示
请添加图片描述

注意

不是很建议表单嵌套十分复杂的数据类型,如果有这种需求建议打平,然后自己再组装,如果不追求性能忽略这条。

;