| Name | Description |
|---|---|
header | 表单顶部区域 |
footer | 表单底部区域 |
submit | 提交区域 |
在表单字段上方添加自定义内容,适用于显示表单标题、说明文案或警告信息:
<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({
username: afz.string().min(3).meta({ label: '用户名' }),
email: afz.email().meta({ label: '邮箱' }),
age: afz.number().min(18).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 #header>
<UAlert
color="primary"
variant="subtle"
icon="i-lucide-info"
title="欢迎注册"
description="请填写以下信息完成注册,所有字段均为必填项"
class="mb-6"
/>
</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({
username: afz.string().min(3).meta({ label: '用户名' }),
role: afz.enum(['admin', 'user', 'guest']).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 #footer="{ state }">
<UCard class="mt-6">
<div class="flex items-center justify-between text-sm mb-2">
<span class="text-gray-600 dark:text-gray-400">表单完成度</span>
<UBadge color="primary" variant="subtle">
{{ Object.keys(state).filter(k => state[k as keyof Schema]).length }} / {{
Object.keys(schema.shape).length }}
</UBadge>
</div>
<UProgress
:value="(Object.keys(state).filter(k => state[k as keyof Schema]).length / Object.keys(schema.shape).length) * 100"
color="primary"
/>
</UCard>
</template>
</MAutoForm>
</UCard>
</template>
完全控制提交按钮及其周围的逻辑和 UI,适用于实现多步骤提交、自定义按钮组或条件提交逻辑。
:submit-button="false" 禁用默认按钮。<script lang="ts" setup>
import { sleep } from '@movk/core'
import type { FormSubmitEvent } from '@nuxt/ui'
import type { z } from 'zod/v4'
const toast = useToast()
const { afz } = useAutoForm()
const autoForm = useTemplateRef('autoForm')
const schema = afz.object({
username: afz.string().min(3, '用户名至少 3 个字符').meta({ label: '用户名' }),
email: afz.email('请输入有效的邮箱地址').default('test@example.com').meta({ label: '邮箱' }),
password: afz.string({ type: 'withPasswordToggle' }).min(8, '密码至少 8 个字符').meta({ label: '密码' }),
agreeToTerms: afz.boolean({ controlProps: { label: '我同意服务条款和隐私政策' } }).meta({ label: '同意条款' })
})
type Schema = z.output<typeof schema>
const form = ref<Partial<Schema>>({})
const isSubmitting = ref(false)
function clearForm() {
autoForm.value?.clear()
}
function resetForm() {
autoForm.value?.reset()
}
async function onSubmit(event: FormSubmitEvent<Schema>) {
isSubmitting.value = true
await sleep(2000)
toast.add({
title: '提交成功',
color: 'success',
description: JSON.stringify(event.data, null, 2)
})
isSubmitting.value = false
}
</script>
<template>
<UCard>
<MAutoForm
ref="autoForm"
:schema="schema"
:state="form"
:submit-button="false"
@submit="onSubmit"
>
<template #submit="{ loading, errors, fields, state }">
<div class="space-y-4">
<div class="flex items-center justify-between p-4 bg-gray-50 dark:bg-gray-800 rounded-lg">
<div class="flex items-center gap-2">
<UIcon
:name="Object.keys(errors).length > 0 ? 'i-lucide-circle-alert' : 'i-lucide-circle-check'"
:class="Object.keys(errors).length > 0 ? 'text-red-500' : 'text-green-500'"
/>
<span class="text-sm font-medium">
{{ Object.keys(errors).length > 0 ? '请修复表单错误' : '表单准备就绪' }}
</span>
</div>
<div class="text-xs text-gray-500 dark:text-gray-400">
已填写 {{ Object.keys(state).filter(k => state[k as keyof Schema] !== undefined && state[k as keyof Schema]
!== '').length }} / {{ fields.length }} 字段
</div>
</div>
<div class="flex gap-3">
<UButton
type="submit"
:loading="loading || isSubmitting"
color="primary"
size="lg"
icon="i-lucide-user-plus"
:disabled="!form.agreeToTerms"
>
{{ loading || isSubmitting ? '正在注册...' : '创建账户' }}
</UButton>
<UButton
type="button"
variant="outline"
color="neutral"
size="lg"
icon="i-lucide-rotate-ccw"
@click="resetForm()"
>
重置
</UButton>
<UButton
type="button"
variant="outline"
color="neutral"
size="lg"
icon="i-lucide-eraser"
@click="clearForm()"
>
清空
</UButton>
</div>
<UAlert
v-if="Object.keys(errors).length > 0"
color="error"
variant="subtle"
icon="i-lucide-triangle-alert"
title="表单验证失败"
>
<template #description>
<ul class="mt-2 space-y-1">
<li v-for="(error, field) in errors" :key="field" class="text-sm">
• {{ error }}
</li>
</ul>
</template>
</UAlert>
</div>
</template>
</MAutoForm>
</UCard>
</template>
| Name | Type | Description |
|---|---|---|
errors | FormError[] | 表单所有错误列表 |
loading | boolean | 表单提交加载状态 |
fields | AutoFormField[] | 字段配置列表 |
state | FormState | 表单当前状态 |