自定义控件

View source
注册和使用自定义 Vue 组件作为表单字段的渲染控件,扩展 AutoForm 的功能。

概述

AutoForm 允许你注册自定义 Vue 组件作为表单字段的渲染控件。这使得你可以扩展 AutoForm 的功能,使用任何 UI 组件库或自定义组件来渲染特定类型的字段。

自定义控件适用于以下场景:

  • 集成第三方组件库(如富文本编辑器、颜色选择器等)
  • 实现特定业务逻辑的输入控件
  • 复用现有的表单组件
  • 为特定字段类型提供统一的渲染方式

基本用法

通过 useAutoForm composable 注册自定义控件:

import { RichTextEditor } from '#components'

const { afz, controls } = useAutoForm({
  // 注册控件类型为 'richtext'
  richtext: {
    component: RichTextEditor,
    controlProps: { class: 'w-full' }
  }
})

然后在 schema 中使用自定义控件:

const schema = afz.object({
  content: afz
    .string({
      type: 'richtext',  // 指定使用自定义控件
      controlProps: {
        readonly: false
      }
    })
    .meta({
      label: '文章内容',
      description: '使用富文本编辑器编写文章内容'
    })
})

最后将 controls 传递给 AutoForm 组件:

<MAutoForm
  :schema="schema"
  :state="form"
  :controls="controls"
  @submit="onSubmit"
/>

控件组件要求

自定义控件组件需要满足以下要求:

  1. 接受 v-model:组件必须支持 v-model 绑定
<script setup>
// 使用 defineModel (Vue 3.4+)
const modelValue = defineModel()

// 或使用 props + emit
const props = defineProps<{
  modelValue: any
}>()

const emit = defineEmits<{
  'update:modelValue': [value: any]
}>()
</script>
  1. 接收 controlProps:组件应该能够接收并处理传入的 props
<script setup>
defineProps<{
  modelValue: string
  readonly?: boolean
  placeholder?: string
  // 其他自定义 props...
}>()
</script>

示例

请输入一个简洁明了的标题

选择文章分类

使用富文本编辑器编写文章内容

添加相关标签

勾选后文章将立即发布

<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'
import { RichTextEditor } from '#components'

const toast = useToast()
const { afz, controls } = useAutoForm({
  richtext: { component: RichTextEditor, controlProps: { class: 'w-full' } }
})

const schema = afz.object({
  title: afz
    .string({ controlProps: { placeholder: '请输入文章标题' } })
    .min(1, '标题不能为空')
    .meta({
      label: '文章标题',
      description: '请输入一个简洁明了的标题'
    }),

  category: afz
    .enum(['tech', 'design', 'business', 'lifestyle'])
    .default('tech')
    .meta({
      label: '分类',
      description: '选择文章分类'
    }),

  content: afz
    .string({
      type: 'richtext',
      controlProps: {
        readonly: false
      }
    })
    .min(10, '内容至少需要 10 个字符')
    .meta({
      label: '文章内容',
      description: '使用富文本编辑器编写文章内容'
    }),

  tags: afz
    .array(afz.string(), { type: 'inputTags' })
    .default(['nuxt', 'vue'])
    .meta({
      label: '标签',
      description: '添加相关标签'
    }),

  publishImmediately: afz
    .boolean()
    .default(false)
    .meta({
      label: '立即发布',
      description: '勾选后文章将立即发布'
    })
})

type Schema = z.output<typeof schema>

const form = ref<Partial<Schema>>({})

async function onSubmit(event: FormSubmitEvent<Schema>) {
  toast.add({
    title: '提交成功',
    color: 'success',
    description: '文章已保存,查看控制台输出。'
  })
  console.log('提交的数据:', event.data)
}
</script>

<template>
  <UCard>
    <MAutoForm
      :schema="schema"
      :state="form"
      :controls="controls"
      @submit="onSubmit"
    />
  </UCard>
</template>

注意事项

类型推断 使用自定义控件时,Zod schema 的类型推断仍然基于底层的数据类型(如 string()number() 等),而不是控件类型。
Props 合并useAutoForm 中的 controlProps 和字段级别的 controlProps 会进行浅合并,字段级别的配置优先级更高。
组件导入 确保自定义控件组件已正确导入。在 Nuxt 项目中,可以使用 #components 自动导入,或手动导入组件。
Copyright © 2025 - 2025 YiXuan - MIT License