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

如何在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会自动触发客户端验证,只有验证通过才会执行你传入的回调,错误会自动同步到errors store。
  • shadcn组件联动:Form.Field通过{form}属性与superForm绑定,Form.FieldErrors会自动读取对应字段的错误并显示,无需手动设置。
  • 实时验证配置:通过validateOnBlur、validateOnInput可以控制验证触发时机,优化用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 09:40:22