field-content, field-before, field-after)仅适用于对象字段和数组字段,不适用于基础类型字段(如 string, number, boolean 等)。field-default 插槽来自定义输入控件。| Name | Description |
|---|---|
field-before:{path} | 在字段渲染之前插入自定义内容,不影响字段本身的渲染 |
field-after:{path} | 在字段渲染之后插入自定义内容,不影响字段本身的渲染 |
field-content:{path} | 完全替换字段的默认渲染逻辑 |
完全替换对象或数组字段的默认渲染,适用于需要完全自定义字段内容的场景:
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'
const toast = useToast()
const { afz } = useAutoForm()
const schema = afz.object({
email: afz.email().meta({ label: '邮箱' }).default('test@example.com'),
notifications: afz.object({
email: afz.boolean().meta({ label: 'Email 通知' }),
sms: afz.boolean().meta({ label: 'SMS 通知' }),
push: afz.boolean().meta({ label: 'Push 通知' })
}).meta({ label: '通知设置' })
})
type Schema = z.output<typeof schema>
const form = ref<Partial<Schema>>({})
async function onSubmit(event: FormSubmitEvent<Schema>) {
toast.add({
title: '提交成功',
color: 'success',
description: JSON.stringify(event.data, null, 2)
})
}
</script>
<template>
<UCard>
<MAutoForm
:schema="schema"
:state="form"
:global-meta="{ collapsible: { defaultOpen: true } }"
@submit="onSubmit"
>
<template #field-default:email="{ value, error, setValue }">
<UInput
:model-value="value"
type="email"
placeholder="your@email.com"
icon="i-lucide-mail"
class="w-full"
:trailing-icon="value ? 'i-lucide-circle-check' : undefined"
:color="error ? 'error' : 'primary'"
@update:model-value="setValue"
/>
</template>
<template #field-content:notifications="{ value, setValue }">
<UCard>
<div class="space-y-3">
<div
v-for="key in ['email', 'sms', 'push']"
:key="key"
class="flex items-center justify-between p-3 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors cursor-pointer"
@click="setValue(key, !value?.[key as keyof typeof value])"
>
<div class="flex items-center gap-3">
<UIcon
:name="key === 'email' ? 'i-lucide-mail' : key === 'sms' ? 'i-lucide-message-square' : 'i-lucide-bell'"
class="size-5"
/>
<div>
<p class="font-medium text-sm capitalize">
{{ key }} 通知
</p>
<p class="text-xs text-gray-500">
{{ key === 'email' ? '接收邮件通知' : key === 'sms' ? '接收短信通知' : '接收推送通知' }}
</p>
</div>
</div>
<UCheckbox disabled :model-value="value?.[key as keyof typeof value]" />
</div>
</div>
</UCard>
</template>
</MAutoForm>
</UCard>
</template>
在字段渲染之前插入内容,常用于添加分隔线、标题或说明信息:
type 覆盖了默认控件(如数组字段使用 inputTags),field-before 插槽将不会生效。<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'
const toast = useToast()
const { afz } = useAutoForm()
const schema = afz.object({
profile: afz.object({
firstName: afz.string().meta({ label: '名' }),
lastName: afz.string().meta({ label: '姓' }),
age: afz.number().min(0).meta({ label: '年龄' })
}).meta({ label: '个人资料' }),
skills: afz.array(afz.string(), {
type: 'inputTags',
controlProps: { icon: 'i-lucide-briefcase' }
})
.default(['编程', '设计'])
.meta({ label: '技能列表' })
})
type Schema = z.output<typeof schema>
const form = ref<Partial<Schema>>({})
async function onSubmit(event: FormSubmitEvent<Schema>) {
toast.add({
title: '提交成功',
color: 'success',
description: JSON.stringify(event.data, null, 2)
})
}
</script>
<template>
<UCard>
<MAutoForm
:global-meta="{ collapsible: { defaultOpen: true } }"
:schema="schema"
:state="form"
@submit="onSubmit"
>
<template #field-before:profile>
<USeparator icon="i-lucide-circle-user" label="个人资料" />
</template>
<template #field-description:skills="{ value }">
{{ value?.length || 0 }} 项已添加技能
</template>
</MAutoForm>
</UCard>
</template>
在字段渲染之后插入内容,常用于添加提示信息、统计数据或验证反馈:
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'
const toast = useToast()
const { afz } = useAutoForm()
const schema = afz.object({
address: afz.object({
street: afz.string().meta({ label: '街道' }),
city: afz.string().meta({ label: '城市' }),
zipCode: afz.string().meta({ label: '邮编' })
}).meta({ label: '地址信息', collapsible: { defaultOpen: true } }),
skills: afz.array(afz.string(), {
type: 'inputTags',
controlProps: { icon: 'i-lucide-briefcase' }
})
.default(['Vue', 'TypeScript', 'Zod', 'Nuxt', 'UI'])
.meta({ label: '技能标签' })
})
type Schema = z.output<typeof schema>
const form = ref<Partial<Schema>>({})
async function onSubmit(event: FormSubmitEvent<Schema>) {
toast.add({
title: '提交成功',
color: 'success',
description: JSON.stringify(event.data, null, 2)
})
}
</script>
<template>
<UCard>
<MAutoForm :schema="schema" :state="form" @submit="onSubmit">
<template #field-after:address="{ value }">
<UAlert
v-if="value && value.street && value.city && value.zipCode"
color="success"
variant="subtle"
icon="i-lucide-check-circle"
class="mt-4"
>
<template #title>
地址验证通过
</template>
<template #description>
完整地址: {{ value.street }}, {{ value.city }}, {{ value.zipCode }}
</template>
</UAlert>
</template>
<template #field-hint:skills="{ value }">
<UBadge
v-if="value && value.length >= 5"
color="success"
variant="subtle"
icon="i-lucide-award"
>
技能丰富
</UBadge>
</template>
</MAutoForm>
</UCard>
</template>
使用 field-content 插槽完全自定义数组字段的渲染逻辑:
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'
const toast = useToast()
const { afz } = useAutoForm()
const schema = afz.object({
tasks: afz.array(
afz.object({
title: afz.string().min(1).meta({ label: '标题' }),
priority: afz.enum(['low', 'medium', 'high']).default('medium').meta({ label: '优先级' }),
completed: afz.boolean().meta({ label: '已完成' })
})
).default([
{ title: '完成项目文档', priority: 'high', completed: false },
{ title: '代码审查', priority: 'medium', completed: false }
]).meta({ label: '任务列表' })
})
type Schema = z.output<typeof schema>
const form = ref<Partial<Schema>>({})
async function onSubmit(event: FormSubmitEvent<Schema>) {
toast.add({
title: '提交成功',
color: 'success',
description: JSON.stringify(event.data, null, 2)
})
}
// 获取优先级颜色
function getPriorityColor(priority: string) {
const priorityStr = String(priority)
switch (priorityStr) {
case 'high': return 'error'
case 'medium': return 'warning'
case 'low': return 'success'
default: return 'neutral'
}
}
// 获取优先级文本
function getPriorityText(priority: string) {
const priorityStr = String(priority)
switch (priorityStr) {
case 'high': return '高'
case 'medium': return '中'
case 'low': return '低'
default: return priorityStr || '未设置'
}
}
</script>
<template>
<UCard>
<MAutoForm
:schema="schema"
:state="form"
:global-meta="{ collapsible: { defaultOpen: true } }"
@submit="onSubmit"
>
<template #field-content:tasks="{ path, value, setValue, state }">
<div class="space-y-4">
<UAlert
color="success"
variant="subtle"
icon="i-lucide-list-checks"
title="任务列表"
description="管理您的任务列表 - 使用 setValue 简化数组操作"
>
<template #actions>
<UBadge :color="!!value?.length ? 'success' : 'neutral'" variant="subtle" size="lg">
{{ value?.length || 0 }} 项
</UBadge>
</template>
</UAlert>
<div v-if="value" class="space-y-3">
<div
v-for="(task, index) in value"
:key="index"
class="relative p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors group"
>
<div class="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition-opacity">
<UButton
icon="i-lucide-trash-2"
color="error"
variant="ghost"
size="xs"
@click="setValue(value.filter((_, i) => i !== index))"
/>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 items-start">
<UFormField :label="`任务 ${index + 1}`" :name="`${path}[${index}].title`" required>
<UInput
:model-value="task?.title"
placeholder="请输入任务标题"
icon="i-lucide-pencil-line"
@update:model-value="setValue(`[${index}].title`, $event)"
/>
</UFormField>
<UFormField label="优先级" :name="`${path}[${index}].priority`">
<USelect
:model-value="task?.priority"
placeholder="选择优先级"
:items="[
{ value: 'low', label: '低优先级' },
{ value: 'medium', label: '中优先级' },
{ value: 'high', label: '高优先级' }
]"
@update:model-value="setValue(`[${index}].priority`, $event)"
>
<template #leading="{ modelValue }">
<UBadge
v-if="modelValue"
:color="getPriorityColor(modelValue)"
variant="subtle"
size="xs"
>
{{ getPriorityText(modelValue) }}
</UBadge>
</template>
</USelect>
</UFormField>
<UFormField label="完成状态" :name="`${path}[${index}].completed`">
<USwitch
:model-value="task?.completed"
unchecked-icon="i-lucide-x"
checked-icon="i-lucide-check"
:label="task?.completed ? '已完成' : '进行中'"
@update:model-value="setValue(`[${index}].completed`, $event)"
/>
</UFormField>
</div>
<div class="mt-3 flex items-center gap-2">
<UBadge
v-if="task?.priority"
:color="getPriorityColor(task.priority)"
variant="subtle"
size="xs"
>
{{ getPriorityText(task.priority) }}优先级
</UBadge>
<UBadge
v-if="task?.completed"
color="success"
variant="subtle"
size="xs"
>
已完成
</UBadge>
<UBadge
v-else
color="warning"
variant="subtle"
size="xs"
>
进行中
</UBadge>
</div>
</div>
</div>
<UAlert
v-if="!state.tasks || state.tasks.length === 0"
color="neutral"
variant="subtle"
icon="i-lucide-inbox"
title="暂无任务"
description="点击添加按钮创建第一个任务"
/>
</div>
</template>
</MAutoForm>
</UCard>
</template>
使用 field-content 插槽自定义嵌套对象字段的渲染逻辑:
<script lang="ts" setup>
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'
const toast = useToast()
const { afz } = useAutoForm()
const schema = afz.object({
profile: afz.object({
name: afz.string().min(2).meta({ label: '姓名' }),
email: afz.email().meta({ label: '邮箱' }),
bio: afz.string().optional().meta({ label: '简介' })
}).meta({ label: '个人资料' }),
contact: afz.object({
$layout: afz.layout({
class: 'grid grid-cols-2 gap-4',
fields: {
phone: afz.string().optional().meta({ label: '电话' }),
website: afz.url().optional().meta({ label: '网站' })
}
})
}).meta({ label: '联系方式' })
})
type Schema = z.output<typeof schema>
const form = ref<Partial<Schema>>({})
async function onSubmit(event: FormSubmitEvent<Schema>) {
toast.add({
title: '提交成功',
color: 'success',
description: JSON.stringify(event.data, null, 2)
})
}
</script>
<template>
<UCard>
<MAutoForm
:schema="schema"
:state="form"
:global-meta="{ collapsible: { defaultOpen: true } }"
@submit="onSubmit"
>
<template #field-content:profile="{ path, value, setValue }">
<UAlert
color="primary"
variant="subtle"
icon="i-lucide-user"
title="个人资料"
description="完善您的个人信息"
/>
<div class="grid grid-cols-2 gap-4">
<UFormField label="姓名" :name="`${path}.name`" required>
<UInput
:model-value="value?.name"
placeholder="请输入您的姓名"
icon="i-lucide-user"
class="w-full"
@update:model-value="setValue('name', $event)"
/>
</UFormField>
<UFormField label="电子邮箱" :name="`${path}.email`" required>
<UInput
:model-value="value?.email"
placeholder="请输入您的电子邮箱"
icon="i-lucide-mail"
type="email"
class="w-full"
@update:model-value="setValue('email', $event)"
/>
</UFormField>
</div>
<UFormField label="简介" :name="`${path}.bio`" hint="可选">
<UTextarea
:model-value="value?.bio"
placeholder="请输入您的个人简介"
:rows="3"
resize
class="w-full"
@update:model-value="setValue('bio', $event)"
/>
</UFormField>
</template>
<template #field-before:contact="{ value, path }">
<UAlert
color="neutral"
variant="subtle"
icon="i-lucide-book-user"
title="联系方式"
description="提供您的联系信息,方便其他人与您交流"
/>
<p class="text-gray-600 dark:text-gray-400 text-xs">
{{ path }} 数据 :{{ value }}
</p>
</template>
</MAutoForm>
</UCard>
</template>
内容插槽接收以下参数:
| Name | Type | Description |
|---|---|---|
state | FormState | 表单数据 |
path | string | 字段路径 |
value | any | 当前字段值 |
setValue | SetValueFn | 设置字段值的函数,支持相对路径 |
errors | unknown[] | 字段错误列表 |
loading | boolean | 表单加载状态 |
setValue 支持相对路径更新子字段,详见 setValue 函数详解。