Vue3+ts----根据配置项,动态生成表单

这里使用的UI框架是ElementPlus,更换其他组件直接更换constant.ts中的type配置和对应的Form组件即可.
思路:
1.这里需要使用h函数方便控制要渲染的表单
2.传递type作为组件或html元素进行渲染,
3.默认包一层El-form,每个数组项会包一个El formItem
4.传入formDataKey,对绑定的表单项进行映射

export const DyForm = defineComponent(
  (props, { emit }) => {
    const form = computed({
      get() {
        return props.modelValue
      },
      set() {
        return false
      }
    })
    const rederChild = () => props.dyFormConfig.map((item: any) => {
      const traverChildren = (child: any[]): any[] => {
        return child.map(
          item => {
            if (typeof item.children === 'string') {
              return h(item.type, item.children)
            }
            return h(item.type, item.formDataKey ?
              {
                ...item.formConfig,
                modelValue: form.value[item.formDataKey],
                'onUpdate:modelValue': (value: any) => emit('update:modelValue', { ...props.modelValue, [item.formDataKey]: value })
              } : item.formConfig,
              { default: () => item.children && traverChildren(item.children) })
          }
        )
      }
      const renderSlots = () => {
        return Object.keys(item.slots).map((slot: any) => {

          return item.slots[slot]()
        })
      }
      return h(ElFormItem, { ...item.formItemConfig }, [
        h(
          item.type,
          item.formDataKey ?
            {
              ...item.formConfig,
              modelValue: form.value[item.formDataKey],
              'onUpdate:modelValue': (value: any) => emit('update:modelValue', { ...props.modelValue, [item.formDataKey]: value })
            } : item.formConfig,
          {
            default: () => item.slots ? renderSlots() : traverChildren(item.children || [])
          }
        )
      ])
    })
    return () => {
      return h(ElForm, {
        model: form,
        ...props.formConfig
      }, {
        default: rederChild()
      })
    }
  },
  // 其他选项,例如声明 props 和 emits。
  {
    props: ['modelValue', 'onSubmit', 'dyFormConfig', 'formConfig'],
    emits: ['update:modelValue']
  }
)

创建一个静态文件存放配置


export class UserForm {
    name?: string
    organization?: string
    date1?: string
    date2?: string
    delivery?: boolean
    type?: []
    resource?: string
    desc?: string
}
interface FormItemConfig<T>{
    type:any
    formConfig?: Record<string, any>
    formDataKey?: T,
    formItemConfig?: Record<string, any>
    children?: FormItemConfig<T>[] | string
    slots?:Record<string,()=>any>
}

export const dyFormConfig:FormItemConfig<keyof UserForm>[] = [
    {
        type: ElInput,
        formItemConfig: {
            label: '请输入姓名'
        },
        formConfig: {
        },
        formDataKey:'name'
    },
    {
        type: ElSelect,
        formItemConfig: {
            label: '请选择组织'
        },
        formConfig: {
            placeholder: '请选择您的组织'
        },
        formDataKey: 'organization',
        children: [
            {
                type: ElOption,
                formConfig: { label: '个人', value: 'person' }
            },
            {
                type: ElOption,
                formConfig: { label: '公司', value: 'company' }
            }
        ]
    },
    {
        type: 'div',
        formItemConfig: {
            label: "请选择时间"
        },
        formConfig: {
            style: 'width:100%;display:flex;',
        },
        children: [
            {
                type: ElCol,
                formConfig: {
                    span: 11
                },
                formItemConfig: {
                    label: '请选择日期'
                },
                children: [
                    {
                        type: ElDatePicker,
                        formDataKey: 'date1',

                        formConfig: {

                            type: 'date',
                            placeholder: '选择日期',
                            style: 'width: 100%'
                        }
                    }
                ]
            },
            {
                type: ElCol,
                formConfig: {
                    span: 2,
                    class: 'text-center'
                },
                children: [
                    {
                        type: 'span',
                        formConfig: {
                            class: 'text-gray-500'
                        },
                        children:'-'
                    }
                ]
            },
            {
                type: ElCol,
                formConfig: {
                    span: 11,
                    class: 'text-center'
                },
                children: [
                    {
                        type: ElDatePicker,
                        formDataKey: 'date2',
                        formConfig: {
                            type: 'date',
                            placeholder: '选择日期',
                            style: 'width: 100%'
                        }
                    }
                ]
            }
        ]
    },
    {
        type: ElButton,
        formConfig: {
            type: 'danger'
        },
        slots: {
            default: () => '确认'
        }
    }
];

使用示例

<script setup lang="ts">
import { DyForm } from './components/DyForm/DyForm';
import { dyFormConfig, UserForm } from './utils/constant'

const form = ref<UserForm>({
    name: '',
    organization: '',
    date1: '',
    date2: '',
    delivery: false,
    type: [],
    resource: '',
    desc: ''
});
const onSubmit = () => {
    console.log(form.value);
};
const formConfig = {
  labelWidth: '120px',
  style: {
    width:'800px'
  }
};

</script>

<template>
    <DyForm v-model="form" :onSubmit="onSubmit" :dyFormConfig="dyFormConfig" :formConfig="formConfig" />
</template>

你可能感兴趣的:(javascript,前端,react.js)