所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

Vue3 + Zod 完美结合:TypeScript 优先的表单验证解决方案

概述

Zod 是一个 TypeScript 优先的模式验证库,提供强大的运行时类型检查和数据验证功能。在 Vue3 项目中集成 Zod,可以显著提升代码的类型安全性和数据验证能力。

主要优势

  • 类型安全:编译时和运行时双重类型保护
  • 简洁易用:声明式 API,学习成本低
  • 功能强大:支持复杂的数据结构和自定义验证规则
  • Vue3 友好:与 Composition API 完美结合

安装

npm install zod
# 或
yarn add zod
# 或
pnpm add zod

基础用法

创建验证模式

import { z } from "zod";

// 基础类型验证
const userSchema = z.object({
  id: z.number(),
  name: z.string().min(1, "姓名不能为空"),
  email: z.string().email("邮箱格式不正确"),
  age: z.number().min(18, "年龄必须大于18岁").optional(),
  isActive: z.boolean().default(true),
});

// 类型推断
type User = z.infer<typeof userSchema>;

数据验证

// 安全解析
const result = userSchema.safeParse({
  id: 1,
  name: "张三",
  email: "zhangsan@example.com",
  age: 25,
});

if (result.success) {
  console.log("验证成功:", result.data);
} else {
  console.log("验证失败:", result.error.issues);
}

// 直接解析(会抛出异常)
try {
  const user = userSchema.parse(invalidData);
} catch (error) {
  console.error("验证失败:", error);
}

Vue3 组件实践

表单验证组件

<template>
  <div
    class="min-h-screen bg-gray-50 flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"
  >
    <div class="max-w-md w-full space-y-8">
      <div>
        <h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
          登录
        </h2>
      </div>

      <form @submit.prevent="handleSubmit" class="mt-8 space-y-6">
        <div class="space-y-4">
          <div>
            <label class="block text-sm font-medium text-gray-700 mb-1"
              >姓名</label
            >
            <input
              v-model="form.name"
              type="text"
              @input="clearError('name')"
              :class="[
                'appearance-none rounded-md relative block w-full px-3 py-2 border placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm',
                errors.name ? 'border-red-500' : 'border-gray-300',
              ]"
              placeholder="请输入您的姓名"
            />
            <span v-if="errors.name" class="mt-1 text-sm text-red-600">{{
              errors.name
            }}</span>
          </div>

          <div>
            <label class="block text-sm font-medium text-gray-700 mb-1"
              >邮箱</label
            >
            <input
              v-model="form.email"
              type="email"
              @input="clearError('email')"
              :class="[
                'appearance-none rounded-md relative block w-full px-3 py-2 border placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm',
                errors.email ? 'border-red-500' : 'border-gray-300',
              ]"
              placeholder="请输入您的邮箱"
            />
            <span v-if="errors.email" class="mt-1 text-sm text-red-600">{{
              errors.email
            }}</span>
          </div>
        </div>

        <div>
          <button
            type="submit"
            class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-150 ease-in-out"
          >
            提交
          </button>
        </div>
      </form>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, reactive } from "vue";
import { z } from "zod";

// 定义验证模式
const userSchema = z.object({
  name: z.string().min(1, "姓名不能为空"),
  email: z.string().email("邮箱格式不正确"),
});

type UserForm = z.infer<typeof userSchema>;

// 表单数据
const form = reactive<UserForm>({
  name: "",
  email: "",
});

// 错误信息
const errors = reactive<Partial<Record<keyof UserForm, string>>>({});

// 清除指定字段的错误信息
const clearError = (field: keyof UserForm) => {
  if (errors[field]) {
    delete errors[field];
  }
};

// 验证表单
const validateForm = () => {
  const result = userSchema.safeParse(form);

  if (!result.success) {
    Object.keys(errors).forEach((key) => delete errors[key as keyof UserForm]);
    result.error.issues.forEach((issue) => {
      if (issue.path[0]) {
        errors[issue.path[0] as keyof UserForm] = issue.message;
      }
    });
    return false;
  }

  Object.keys(errors).forEach((key) => delete errors[key as keyof UserForm]);
  return true;
};

// 提交处理
const handleSubmit = () => {
  if (validateForm()) {
    console.log("表单数据:", form);
    alert("表单提交成功!");
  } else {
    console.log("表单验证失败");
  }
};
</script>

高级用法

自定义验证逻辑

const conditionalSchema = z
  .object({
    type: z.enum(["individual", "company"]),
    name: z.string(),
    email: z.string().email(),
    companyName: z.string().optional(),
  })
  .refine(
    (data) => {
      if (data.type === "company" && !data.companyName) {
        return false;
      }
      return true;
    },
    {
      message: "公司类型必须填写公司名称",
      path: ["companyName"],
    }
  );

自定义验证器

const customSchema = z.custom(
  (value) => typeof value === "string",
  "Expected string, received number"
);
console.log(customSchema.parse("hello")); // hello
console.log(customSchema.parse(123)); // ZodError: Expected string, received number

总结

Zod 在 Vue3 项目中的应用提供了强大的类型安全和数据验证能力。通过合理使用 Zod,可以:

  • 提升代码的类型安全性
  • 简化表单验证逻辑
  • 确保 API 数据的完整性
  • 提供更好的开发体验
原文链接:https://code.ifrontend.net/archives/1281,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?