Object

View source
Object 字段类型的使用方法和配置选项

基础用法

使用 afz.object() 创建对象字段:

通用对象

通用对象类型通常与 selectMenu 结合使用,用于选择复杂数据结构:

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

const { afz } = useAutoForm()
const toast = useToast()

const { data: users } = await useFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'typicode-users-basic',
  transform: (data: { id: number, name: string }[]) => {
    return data?.map(user => ({
      label: user.name,
      value: String(user.id),
      avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
    }))
  }
})

const schema = afz.object({
  name: afz.string().min(1, '请输入姓名').default('张三'),
  age: afz.number().min(1).max(150).default(30),
  email: afz.email('请输入有效的邮箱地址').default('zhangsan@example.com'),
  user: afz.object({
    label: afz.string(),
    value: afz.string(),
    avatar: afz.object({ src: afz.url() })
  }, {
    type: 'selectMenu',
    controlProps: ({ value }: { value: { avatar: { src: string } } }) => ({
      placeholder: '请选择用户',
      items: users.value,
      avatar: value?.avatar
    })
  })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: '提交成功',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

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

嵌套对象

嵌套对象结构,支持折叠展开:

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

const { afz } = useAutoForm()
const toast = useToast()

const schema = afz.object({
  user: afz.object({
    name: afz.string(),
    email: afz.email()
  }).meta({ label: '用户信息', collapsible: { defaultOpen: true } }),
  address: afz.object({
    street: afz.string(),
    city: afz.string(),
    zipCode: afz.string()
  }).optional().meta({ label: '地址信息' })
})

async function onSubmit(event: FormSubmitEvent<z.output<typeof schema>>) {
  toast.add({
    title: 'Success',
    color: 'success',
    description: JSON.stringify(event.data, null, 2)
  })
}
</script>

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

类型化对象

使用 TypeScript 接口约束对象结构,在定义 schema 时获得字段名的 IDE 提示:
选择对象类型:
<script lang="ts" setup>
const { afz } = useAutoForm()
const toast = useToast()

interface UserInfo {
  name: string
  age: number
  email: string
}

const userSchema = {
  name: afz.string().min(1, '请输入姓名').default('张三'),
  age: afz.number().min(1).max(150).default(18),
  email: afz.email('请输入有效的邮箱地址').default('example@example.com')
}

const testUser = {
  name: '张三',
  age: 28,
  email: 'test@example.com',
  extraField: '我是额外字段'
}

const normalSchema = afz.object<UserInfo>()(userSchema)
const looseSchema = afz.looseObject<UserInfo>()(userSchema)
const strictSchema = afz.strictObject<UserInfo>()(userSchema)

const currentType = ref<'normal' | 'loose' | 'strict'>('normal')
const items = [
  { label: 'Normal', value: 'normal' },
  { label: 'Loose', value: 'loose' },
  { label: 'Strict', value: 'strict' }
]

const schema = computed(() => {
  switch (currentType.value) {
    case 'loose': return looseSchema
    case 'strict': return strictSchema
    default: return normalSchema
  }
})

async function click() {
  const parsed = schema.value.safeParse(testUser)
  if (!parsed.success) {
    toast.add({
      title: '验证失败',
      color: 'error',
      description: JSON.stringify(parsed.error.issues, null, 2)
    })
  } else {
    toast.add({
      title: '验证成功',
      color: 'success',
      description: JSON.stringify(parsed.data, null, 2)
    })
  }
}
</script>

<template>
  <UCard class="space-y-4">
    <template #header>
      <div class="flex items-center gap-2">
        <span class="text-sm font-medium">选择对象类型:</span>
        <USelect v-model="currentType" :items="items" />
      </div>
    </template>

    <MAutoForm :schema="schema" :submit-button="false">
      <template #footer>
        <UButton color="primary" @click="click">
          验证类型
        </UButton>
      </template>
    </MAutoForm>
  </UCard>
</template>

API

基础调用

// 直接调用
afz.object(shape, meta?)

// 柯里化调用(类型约束)
afz.object<TypeConstraint>()(shape, meta?)

两种调用方式的区别

最常用的方式,直接传入字段定义:

const schema = afz.object({
  name: afz.string(),
  age: afz.number()
})

Shape

定义对象的字段结构,决定输出类型:

const schema = afz.object({
  name: afz.string(),
  age: afz.number(),
  email: afz.email()
})
// 输出类型:{ name: string, age: number, email: string }

Meta

用于覆盖默认控件和配置元数据,支持多种场景:

为嵌套对象添加元数据(label、hint、折叠等):

afz.object({
  user: afz.object({
    name: afz.string(),
    email: afz.email()
  }).meta({
    label: '用户信息',
    collapsible: { defaultOpen: true }
  })
})

对象验证模式

三种对象工厂对应不同的额外字段处理策略:

移除未定义的额外字段:

const schema = afz.object({ name: afz.string() })

schema.parse({ name: '张三', extra: 'removed' })
// 结果:{ name: '张三' }
可以在类型化对象示例中交互式体验三种验证模式的区别。
Copyright © 2025 - 2025 YiXuan - MIT License