Home
avatar

.Demure

表单统一校验或自定义校验

表单提交统一验证

useFormValidation.ts

import { ref } from "vue";
import { ElMessage } from "element-plus";

/**
 * 表单验证规则类型
 */
export interface ValidationRule {
  required?: boolean;
  message: string;
  validator?: (value: any) => boolean;
}

/**
 * 表单验证 Composable
 * 提供统一的表单验证逻辑
 */
export function useFormValidation<T extends Record<string, any>>(
  rules: Record<keyof T, ValidationRule>
) {
  const submitted = ref(false);
  const errors = ref<Record<string, string>>({});

  /**
   * 检查字段是否无效
   */
  const isInvalid = (fieldName: keyof T, value?: any): boolean => {
    if (!submitted.value) return false;

    const rule = rules[fieldName];
    if (!rule) return false;

    // 必填验证
    if (rule.required && (!value || value === "")) {
      return true;
    }

    // 自定义验证器
    if (rule.validator && !rule.validator(value)) {
      return true;
    }

    return false;
  };

  /**
   * 验证单个字段
   */
  const validateField = (fieldName: keyof T, value: any): boolean => {
    const rule = rules[fieldName];
    if (!rule) return true;

    // 清除之前的错误
    delete errors.value[fieldName as string];

    // 必填验证
    if (rule.required && (!value || value === "")) {
      errors.value[fieldName as string] = rule.message;
      return false;
    }

    // 自定义验证器
    if (rule.validator && !rule.validator(value)) {
      errors.value[fieldName as string] = rule.message;
      return false;
    }

    return true;
  };

  /**
   * 验证整个表单
   */
  const validate = (data: T): boolean => {
    submitted.value = true;
    errors.value = {};
    let isValid = true;

    // 遍历所有规则进行验证
    for (const [fieldName, rule] of Object.entries(rules)) {
      const value = data[fieldName as keyof T];

      if (!validateField(fieldName as keyof T, value)) {
        isValid = false;
        // 显示第一个错误消息
        if (Object.keys(errors.value).length === 1) {
          ElMessage.error(rule.message);
        }
      }
    }

    return isValid;
  };

  /**
   * 验证必填字段(快速验证)
   */
  const validateRequired = (data: T): boolean => {
    submitted.value = true;

    for (const [fieldName, rule] of Object.entries(rules)) {
      if (rule.required) {
        const value = data[fieldName as keyof T];
        if (!value || value === "") {
          ElMessage.error(rule.message);
          return false;
        }
      }
    }

    return true;
  };

  /**
   * 重置验证状态
   */
  const resetValidation = () => {
    submitted.value = false;
    errors.value = {};
  };

  /**
   * 获取字段错误消息
   */
  const getFieldError = (fieldName: keyof T): string => {
    return errors.value[fieldName as string] || "";
  };

  /**
   * 检查是否有错误
   */
  const hasErrors = (): boolean => {
    return Object.keys(errors.value).length > 0;
  };

  return {
    submitted,
    errors,
    isInvalid,
    validateField,
    validate,
    validateRequired,
    resetValidation,
    getFieldError,
    hasErrors,
  };
}

/**
 * 常用验证规则
 */
export const CommonValidationRules = {
  required: (message: string): ValidationRule => ({
    required: true,
    message,
  }),

  url: (message: string = "请输入有效的URL"): ValidationRule => ({
    message,
    validator: (value: string) => {
      if (!value) return true; // 非必填时允许空值
      const urlPattern = /^https?:\/\/.+/;
      return urlPattern.test(value);
    },
  }),

  maxLength: (length: number, message?: string): ValidationRule => ({
    message: message || `最多输入${length}个字符`,
    validator: (value: string) => {
      if (!value) return true;
      return value.length <= length;
    },
  }),

  minLength: (length: number, message?: string): ValidationRule => ({
    message: message || `至少输入${length}个字符`,
    validator: (value: string) => {
      if (!value) return true;
      return value.length >= length;
    },
  }),
};
Code

喜欢这篇文章嘛,觉得文章不错的话,奖励奖励我!

支付宝打赏支付宝微信打赏 微信