AutoForm
Legacy根据 Zod 模式自动生成表单。
什么是 AutoForm
AutoForm 是一个即插即用的表单构建器,适用于已有 Zod 模式的内部和低优先级表单。例如,如果您已为 API 准备了 Zod 模式,并希望创建一个简单的管理面板来编辑用户资料,只需将模式传递给 AutoForm 即可完成。
安装
运行以下命令
pnpm dlx shadcn-vue@latest update form
npx shadcn-vue@latest add auto-form
字段类型
目前,以下字段类型已支持开箱即用:
- 布尔值(复选框、开关)
- 日期(日期选择器)
- 枚举(选择器、单选框组)
- 数字(输入框)
- 字符串(输入框、文本域)
- 文件(文件)
您可以通过在 auto-form/constants.ts 中的 INPUT_COMPONENTS 对象中添加其他字段类型来扩展支持。
Zod 配置
验证
表单模式可以使用 Zod 的任何验证方法,包括 refine。
⚠️ 但是,当某些对象键缺失时,Zod 的 refine 和 superRefine 不会执行,这是一个已知问题。 了解更多
描述
您可以使用 describe 方法为每个字段设置标签。如果未设置标签,将使用字段名并取消驼峰命名。
const formSchema = z.object({
username: z.string().describe('您的用户名'),
someValue: z.string(), // 将显示为 "Some Value"
})您也可以通过 fieldConfig 配置标签。
可选字段
默认情况下,所有字段均为必填。您可以使用 optional 方法使字段变为可选。
const formSchema = z.object({
username: z.string().optional(),
})默认值
您可以使用 default 方法为字段设置默认值。
const formSchema = z.object({
favouriteNumber: z.number().default(5),
})如果要设置日期的默认值,请先使用 new Date(val) 将其转换为 Date 对象。
子对象
您可以嵌套对象以创建可折叠的部分。
const formSchema = z.object({
address: z.object({
street: z.string(),
city: z.string(),
zip: z.string(),
// 您可以按需任意深度嵌套对象
nested: z.object({
foo: z.string(),
bar: z.string(),
nested: z.object({
foo: z.string(),
bar: z.string(),
}),
}),
}),
})与普通对象一样,您可以使用 describe 方法为部分设置标签和描述:
const formSchema = z.object({
address: z
.object({
street: z.string(),
city: z.string(),
zip: z.string(),
})
.describe('您的地址'),
})选择/枚举
AutoForm 支持 enum 和 nativeEnum 来创建选择字段。
const formSchema = z.object({
color: z.enum(['red', 'green', 'blue']),
})
enum BreadTypes {
// 对于原生枚举,您也可以定义带背书的枚举以设置自定义标签
White = '白面包',
Brown = '棕面包',
Wholegrain = '全麦面包',
Other,
}
// 请注意,Zod 将验证并返回枚举标签,而不是枚举值!
const formSchema = z.object({
bread: z.nativeEnum(BreadTypes),
})数组
AutoForm 支持对象数组。由于从字符串/数字等数组推断字段标签等元素较为困难,因此仅支持对象数组。
const formSchema = z.object({
guestListName: z.string(),
invitedGuests: z
.array(
// 为每个项目定义字段
z.object({
name: z.string(),
age: z.number(),
})
)
// 可选择设置自定义标签 - 否则将从字段名推断
.describe('受邀参加派对的客人'),
})数组不支持作为表单模式的根元素。
您也可以使用 .default() 设置数组的默认值,但请确保数组元素与模式结构相同。
const formSchema = z.object({
guestListName: z.string(),
invitedGuests: z
.array(
// 为每个项目定义字段
z.object({
name: z.string(),
age: z.number(),
})
)
.describe('受邀参加派对的客人')
.default([
{ name: 'John', age: 24, },
{ name: 'Jane', age: 20, },
]),
})字段配置
由于 Zod 不允许向模式添加其他属性,您可以使用 fieldConfig 属性为每个字段的 UI 添加额外配置。
<template>
<AutoForm
:field-config="{
username: {
// 字段配置
},
}"
/>
</template>标签
如果您想覆盖通过 Zod 描述 预定义的标签,可以使用 label 属性自定义标签。
<template>
<AutoForm
:field-config="{
username: {
label: '自定义用户名',
},
}"
/>
</template>描述
您可以使用 description 属性在字段下方添加描述。
<template>
<AutoForm
:field-config="{
username: {
description: '输入一个唯一的用户名。这将显示给其他用户。',
},
}"
/>
</template>输入属性
您可以使用 inputProps 属性向输入组件传递属性。可以使用 HTML 组件接受的任何属性。
<template>
<AutoForm
:field-config="{
username: {
inputProps: {
type: 'text',
placeholder: '用户名',
},
},
}"
/>
</template>
// 这将渲染为:
<input type="text" placeholder="用户名" />可以通过在 inputProps 中使用 showLabel 属性来禁用输入的标签。
<template>
<AutoForm
:field-config="{
username: {
inputProps: {
type: 'text',
placeholder: '用户名',
showLabel: false,
},
},
}"
/>
</template>组件
默认情况下,AutoForm 将使用 Zod 类型来确定使用哪个输入组件。您可以通过 component 属性覆盖此行为。
<template>
<AutoForm
:field-config="{
acceptTerms: {
// 布尔值默认使用复选框,改用开关
component: 'switch',
},
}"
/>
</template>支持的字段类型的完整列表已类型化。当前支持的类型包括:
checkbox(布尔值默认)switchdate(日期默认)select(枚举默认)radiotextarea
或者,您可以将 Vue 组件传递给 component 属性以使用自定义组件。
在 CustomField.vue 中
<script setup lang="ts">
import type { FieldProps } from './interface'
import { computed } from 'vue'
import { AutoFormLabel } from '@/ui/auto-form'
import { FormControl, FormDescription, FormField, FormItem, FormMessage } from '@/ui/form'
import { Input } from '@/ui/input'
import AutoFormLabel from './AutoFormLabel.vue'
const props = defineProps<FieldProps>()
</script>
<template>
<FormField v-slot="slotProps" :name="fieldName">
<FormItem v-bind="$attrs">
<AutoFormLabel v-if="!config?.hideLabel" :required="required">
{{ config?.label }}
</AutoFormLabel>
<FormControl>
<CustomInput v-bind="slotProps" />
</FormControl>
<FormDescription v-if="config?.description">
{{ config.description }}
</FormDescription>
<FormMessage />
</FormItem>
</FormField>
</template>在 fieldConfig 中传递上述组件。
<template>
<AutoForm
:field-config="{
username: {
component: CustomField,
},
}"
/>
</template>命名插槽
您可以使用 Vue 命名插槽来自定义渲染的 AutoFormField。
<template>
<AutoForm
:field-config="{
customParent: {
label: '包装器',
},
}"
>
<template #customParent="slotProps">
<div class="flex items-end space-x-2">
<AutoFormField v-bind="slotProps" class="w-full" />
<Button type="button">
检查
</Button>
</div>
</template>
</AutoForm>
</template>访问表单数据
有两种方式可以访问表单数据:
@submit
首选方式是使用 submit 事件。当表单提交且数据有效时,将调用此事件。
<template>
<AutoForm
@submit="(data) => {
// 对数据进行操作
}"
/>
</template>受控表单
通过将 form 作为属性传递,您可以控制和使用 Form 提供的方法。
<script setup lang="ts">
import { toTypedSchema } from '@vee-validate/zod'
import { useForm } from 'vee-validate'
import * as z from 'zod'
import { AutoForm } from '@/components/ui/auto-form'
const schema = z.object({
username: z.string(),
})
const form = useForm({
validationSchema: toTypedSchema(schema),
})
form.setFieldValue('username', 'bar')
</script>
<template>
<AutoForm :form="form" :schema="schema" />
</template>提交表单
您可以使用任何 button 组件创建提交按钮。最重要的是添加属性 type="submit"。
<template>
<AutoForm>
<CustomButton type="submit">
立即发送
</CustomButton>
</AutoForm>
// 或
<AutoForm>
<button type="submit">
立即发送
</button>
</AutoForm>
</template>添加其他元素
传递给 AutoForm 组件的所有子元素将渲染在表单下方。
<template>
<AutoForm>
<Button>立即发送</Button>
<p class="text-gray-500 text-sm">
提交此表单即表示您同意我们的
<a href="#" class="text-primary underline">
条款和条件
</a>。
</p>
</AutoForm>
</template>依赖关系
AutoForm 允许您在字段之间添加依赖关系,以根据其他字段的值控制字段。为此,可以向 AutoForm 组件传递一个 dependencies 数组。
<template>
<AutoForm
:dependencies="[
{
// 'age' 字段在年龄为 18 岁或以上时隐藏 'parentsAllowed' 字段
sourceField: 'age',
type: DependencyType.HIDES,
targetField: 'parentsAllowed',
when: age => age >= 18,
},
{
// 'vegetarian' 复选框从 'mealOptions' 中隐藏 'Beef Wellington' 选项
// 如果尚未选中
sourceField: 'vegetarian',
type: DependencyType.SETS_OPTIONS,
targetField: 'mealOptions',
when: (vegetarian, mealOption) =>
vegetarian && mealOption !== 'Beef Wellington',
options: ['Pasta', 'Salad'],
},
]"
/>
</template>支持以下依赖类型:
DependencyType.HIDES:当when函数返回 true 时隐藏目标字段DependencyType.DISABLES:当when函数返回 true 时禁用目标字段DependencyType.REQUIRES:当when函数返回 true 时将目标字段设置为必填DependencyType.SETS_OPTIONS:当when函数返回 true 时将目标字段的选项设置为options数组
when 函数使用源字段的值和目标字段的值调用,并应返回一个布尔值以指示是否应用依赖关系。
请注意,当返回 false 时,依赖关系不会导致相反的操作 - 例如,如果您在 Zod 模式中将字段标记为必填(即未显式设置 optional),在 REQUIRES 依赖中返回 false 不会将其标记为可选。您应改用 Zod 的 optional 方法将其默认标记为可选,并使用 REQUIRES 依赖在满足依赖时将其标记为必填。
请注意,依赖关系对表单的验证没有任何影响。您应使用 Zod 的 refine 方法来根据其他字段的值验证表单。
您可以为同一字段和依赖类型创建多个依赖关系 - 例如,根据多个其他字段隐藏一个字段。当满足任何依赖关系时,这将隐藏该字段。
示例
基础
无标签输入
此示例展示如何使用无标签的 AutoForm 输入。
子对象
根据 Zod 模式自动生成表单。
受控
此示例展示如何以受控方式使用 AutoForm。
确认密码
使用精炼模式验证两个字段是否匹配。
API 示例
表单选择选项从 API 获取。
数组支持
您可以在模式中使用数组以创建动态表单。
依赖关系
在字段之间创建依赖关系。