You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nuxt3中Shadcn-ui Combobox的Zod校验失败问题求助

Nuxt3 + Shadcn Combobox Zod校验不通过的解决办法

问题根源

你手动维护了独立的value变量存储选中项,但没有将其与表单的accountSelected字段同步,导致表单中该字段始终为空字符串,Zod的必填校验自然无法通过。Shadcn的Combobox属于自定义组件,不像原生Input能自动同步值到表单,必须手动将选中值更新到表单字段中。

解决方案

  1. 移除自己定义的value ref,直接使用表单实例提供的form.values.accountSelected存储选中值
  2. 在CommandItem的@select事件中,调用form.setValue()手动更新表单字段
  3. 调整所有依赖选中值的显示逻辑,统一使用form.values.accountSelected

修改后的完整代码

Script部分

<script setup lang="ts">
const accounts = [
    { value: 'nuxt.js', label: 'Nuxt.js' },
    { value: 'remix', label: 'Remix' },
    { value: 'astro', label: 'Astro' },
]
const open = ref(false)

const formSchema = toTypedSchema(z.object({
    accountSelected: z.string({
        required_error: "Account is required"
    }),
    setupName: z.string({
        required_error: "Setup is required"
    })
}))

const form = useForm({
    validationSchema: formSchema,
    // 可选:设置表单初始值,让状态更清晰
    defaultValues: {
        accountSelected: '',
        setupName: ''
    }
})

const submitForm = form.handleSubmit((values) => {
    console.log("form submitted", values);
})
</script>

Template部分

<template>
    <form @submit="submitForm">
        <FormField v-slot="{ componentField }" name="accountSelected">
            <FormItem class="flex flex-col">
                <FormLabel>Select account</FormLabel>
                <FormControl>
                    <Popover v-model:open="open">
                        <PopoverTrigger as-child>
                            <Button variant="outline" role="combobox" :aria-expanded="open">
                                {{ form.values.accountSelected
                                    ? accounts.find((account) => account.value === form.values.accountSelected)?.label
                                    : "Select account..." }}
                                <ChevronsUpDown class="ml-2 h-4 w-4 shrink-0 opacity-50" />
                            </Button>
                        </PopoverTrigger>
                        <PopoverContent>
                            <Command>
                                <CommandInput placeholder="Search account..." />
                                <CommandEmpty>No account found.</CommandEmpty>
                                <CommandList>
                                    <CommandGroup>
                                        <CommandItem 
                                            v-bind="componentField" 
                                            v-for="account in accounts"
                                            :key="account.value" 
                                            :value="account.value" 
                                            @select="(ev) => {
                                                if (typeof ev.detail.value === 'string') {
                                                    // 直接更新表单字段
                                                    form.setValue('accountSelected', ev.detail.value)
                                                }
                                                open = false
                                            }"
                                        >
                                            {{ account.label }}
                                            <Check :class="cn(
                                                'ml-auto h-4 w-4',
                                                form.values.accountSelected === account.value ? 'opacity-100' : 'opacity-0',
                                            )" />
                                        </CommandItem>
                                    </CommandGroup>
                                </CommandList>
                            </Command>
                        </PopoverContent>
                    </Popover>
                </FormControl>
                <FormMessage />
            </FormItem>
        </FormField>
        <FormField v-slot="{ componentField }" name="setupName">
            <FormItem>
                <FormLabel>Name</FormLabel>
                <FormControl>
                    <Input type="text" v-bind="componentField" />
                </FormControl>
                <FormMessage />
            </FormItem>
        </FormField>
        <Button type="submit" class="flex justify-center items-center mt-4">
            Send
        </Button>
    </form>
</template>

关键说明

  • 通过form.setValue('accountSelected', ev.detail.value)将选中值同步到表单字段,Zod就能获取到正确的值进行校验
  • 所有依赖选中状态的逻辑都基于form.values.accountSelected,保证数据与表单状态完全一致

内容的提问来源于stack exchange,提问作者Joey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 06:02:17