Vue 3 + Element Plus 动态表单构建器组件实战教程

Vue 3 + Element Plus 动态表单构建器组件实战教程

✅ 适用技术栈:Vue 3 +

  • formItems:传入的动态表单项配置
  • formConfig:用于传递给 的其他配置
  • rules:校验规则
  • span:每一列的栅格宽度

2️⃣ 表单结构与渲染逻辑(template)



3️⃣ 表单项属性与过滤逻辑

import { ref, computed, h, defineExpose } from 'vue'

const formRef = ref(null)
const defaultLabelWidth = '80px'

const formItemsComputed = computed(() =>
  props.formItems.filter((item) => item.hidden !== true)
)

function getFormItemProps(item) {
  const { formProps = {} } = item
  const { labelCol = {}, ...rest } = formProps
  const formLabelWidth = props.formConfig?.labelCol?.style?.width
  const labelWidth =
    labelCol?.style?.width === '0px' ? formLabelWidth : labelCol?.style?.width
  return {
    labelWidth: labelWidth || defaultLabelWidth,
    ...rest,
  }
}

4️⃣ 动态组件渲染器

const baseFieldReg = /^(type|label|props|on|span|key|hidden|required|rules|col|formProps)$/
const selectType = new Set(['select', 'date', 'time', 'treeSelect'])

const ComponentItem = {
  props: ['item'],
  setup({ item }) {
    const compProps = Object.keys(item).reduce(
      (prev, key) => {
        if (!baseFieldReg.test(key)) prev[key] = item[key]
        return prev
      },
      { ...item.props, formData: model.value }
    )

    if (!('placeholder' in compProps)) {
      const text = selectType.has(item.type) ? '请选择' : '请输入'
      compProps.placeholder = text + item.label
    }

    const tag = getFormItemComponent(item.type)

    return () =>
      h(
        tag,
        {
          ...compProps,
          modelValue: model.value[item.field],
          'onUpdate:modelValue': (val) => {
            model.value[item.field] = val
          },
        },
        item.slots
      )
  },
}
  • 支持根据字段 type 自动选择组件(如 inputel-input
  • 自动生成 placeholder
  • 支持双向绑定 modelValue

5️⃣ 表单校验方法与暴露

function validate() {
  return formRef.value?.validate()
}

defineExpose({
  validate,
  formRef,
  model, // 当前表单数据
})

三、使用示例

✅ 组件调用


✅ 外部数据

const formData = ref({
  name: '',
  gender: '',
})

const formItems = [
  {
    field: 'name',
    label: '姓名',
    type: 'input',
    required: true,
    props: { clearable: true },
  },
  {
    field: 'gender',
    label: '性别',
    type: 'select',
    props: {
      options: [
        { label: '男', value: 'male' },
        { label: '女', value: 'female' },
      ],
    },
  },
]

✅ 校验示例

const formBuilder = ref(null)

const submit = async () => {
  try {
    await formBuilder.value.validate()
    console.log('表单验证通过', formData.value)
  } catch (err) {
    console.warn('表单验证失败', err)
  }
}

四、辅助函数:getFormItemComponent

封装一个组件映射函数:

// getFormItemComponent.js
export function getFormItemComponent(type) {
  const map = {
    input: 'el-input',
    select: 'el-select',
    date: 'el-date-picker',
    time: 'el-time-picker',
    treeSelect: 'el-tree-select',
  }
  return map[type] || 'el-input'
}

✅ 五、结语与扩展方向

你已经成功搭建了一个可配置、可复用、灵活插槽支持的动态表单组件。后续你可以继续扩展:

  • 支持远程 options 数据加载
  • 支持联动字段显示与禁用
  • 支持嵌套表单(数组、多行结构)
  • 支持字段动态规则切换与实时校验
  • 支持表单项动态增删(如动态添加联系人)

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