Nuxt3中Shadcn-ui Combobox的Zod校验失败问题求助
Nuxt3 + Shadcn Combobox Zod校验不通过的解决办法
问题根源
你手动维护了独立的value变量存储选中项,但没有将其与表单的accountSelected字段同步,导致表单中该字段始终为空字符串,Zod的必填校验自然无法通过。Shadcn的Combobox属于自定义组件,不像原生Input能自动同步值到表单,必须手动将选中值更新到表单字段中。
解决方案
- 移除自己定义的
valueref,直接使用表单实例提供的form.values.accountSelected存储选中值 - 在
CommandItem的@select事件中,调用form.setValue()手动更新表单字段 - 调整所有依赖选中值的显示逻辑,统一使用
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
相关产品推荐
相关产品推荐

