如何在Svelte中用shadcn-svelte+Zod实现客户端表单错误展示
解决Svelte + shadcn-svelte + Zod客户端表单验证错误显示问题
核心问题分析
你当前代码存在两个关键问题:
- 手动调用
formSchema.parse后,通过errors.set逐个设置错误时,每次调用都会覆盖之前的错误对象,最终只会显示最后一个字段的错误。 - 没有利用
sveltekit-superforms内置的客户端验证机制,手动处理验证逻辑破坏了superForm与shadcn表单组件的联动。
无需+page.server.ts的正确实现方案
不需要服务端参与时,我们可以直接初始化superForm并传入默认空数据,同时配置内置的Zod客户端验证,让错误自动同步到UI。
步骤1:优化Schema(可选)
some-page/schema.ts保留原有结构,建议添加自定义错误提示提升用户体验:
import { z } from "zod"; export const formSchema = z.object({ email: z.string() .min(2, "邮箱长度不能少于2个字符") .max(50, "邮箱长度不能超过50个字符") .toLowerCase() .email("请输入有效的邮箱地址"), password: z.string() .min(3, "密码长度不能少于3个字符") .toUpperCase() }); export type FormSchema = typeof formSchema;
步骤2:重构+page.svelte代码
移除手动验证逻辑,改用superForm的handleSubmit处理提交,确保表单组件与superForm正确绑定:
<script lang="ts"> import * as Form from "$lib/components/ui/form"; import { Input } from "$lib/components/ui/input"; import { Button } from "$lib/components/ui/button"; import { formSchema, type FormSchema } from "./schema"; import SuperDebug, { superForm } from "sveltekit-superforms"; import { zodClient } from "sveltekit-superforms/adapters"; // 初始化空表单数据,无需依赖服务端返回的data const form = superForm<FormSchema>({ email: "", password: "" }, { validators: zodClient(formSchema), // 可选配置:失焦时触发验证 validateOnBlur: true, // 提交时自动执行验证 validateOnSubmit: true }); const { form: formData, errors, handleSubmit } = form; // 仅在验证通过时执行的提交逻辑 const onSubmit = handleSubmit((validatedData) => { console.log("验证成功,表单数据:", validatedData); // 这里添加你的业务逻辑,比如调用API、跳转页面等 }); </script> <!-- 可选:调试用,查看表单数据和错误状态 --> <SuperDebug data={$formData} /> <SuperDebug data={$errors} /> <form on:submit|preventDefault={onSubmit}> <Form.Field {form} name="email"> <Form.Label>邮箱</Form.Label> <Form.Control let:attrs> <Input type="email" {...attrs} bind:value={$formData.email} aria-invalid={!!$errors.email} /> </Form.Control> <Form.Description>请输入你的注册邮箱</Form.Description> <Form.FieldErrors /> <!-- 自动显示当前字段的错误信息 --> </Form.Field> <Form.Field {form} name="password"> <Form.Label>密码</Form.Label> <Form.Control let:attrs> <Input type="password" {...attrs} bind:value={$formData.password} aria-invalid={!!$errors.password} /> </Form.Control> <Form.Description>请输入至少3位的密码</Form.Description> <Form.FieldErrors /> </Form.Field> <Button type="submit" class="mt-4">提交</Button> </form>
关键要点说明
- 初始化superForm:无服务端时直接传入符合Schema的空对象作为初始数据,替代依赖服务端的
export let data。 - 使用handleSubmit:superForm的
handleSubmit会自动触发客户端验证,只有验证通过才会执行你传入的回调,错误会自动同步到errorsstore。 - shadcn组件联动:
Form.Field通过{form}属性与superForm绑定,Form.FieldErrors会自动读取对应字段的错误并显示,无需手动设置。 - 实时验证配置:通过
validateOnBlur、validateOnInput可以控制验证触发时机,优化用户体验。
内容的提问来源于stack exchange,提问作者kawa
相关产品推荐
相关产品推荐

