JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 55
  • Score
    100M100P100Q95753F
  • License MIT

🚀 The most powerful Vue 3 form validation library with 226+ built-in rules

Package Exports

  • @yojack/vue-supervalidator

Readme

Vue SuperValidator

🚀 The most powerful Vue 3 form validation library with 226+ built-in rules

一个功能强大、使用超简单的 Vue 3 表单校验插件。

NPM Version NPM Downloads License

🌟 为什么选择 Vue SuperValidator?

<!-- 只需一行代码,错误信息自动显示! -->
<input v-validate="'required|email'" name="email" />
  • 🎯 226+ 内置规则 - 包含身份证、银行卡、车牌号等专业验证
  • 超级简单 - 使用指令,错误信息自动显示,无需额外代码
  • 🔐 专业算法 - 身份证校验码、银行卡 Luhn 算法、车牌识别
  • 🌍 国际化 - 支持中国、美国、英国、日本、韩国等多国格式
  • 💪 TypeScript - 100% TypeScript,完整类型支持
  • 🎨 三种使用方式 - 指令、辅助函数、Composition API,满足所有场景

📋 目录

📦 安装

npm install @yojack/vue-supervalidator

🚀 快速开始

本插件提供三种使用方式,从简单到复杂,满足不同场景需求。

方式一:自定义指令(最简单)⭐ 推荐

特点:错误信息自动显示,无需额外代码!

<template>
  <form>
    <!-- 超级简单:一行代码,错误自动显示 -->
    <input v-model="email" v-validate="'required|email'" name="email" />
    <input v-model="phone" v-validate="'required|phone'" name="phone" />
    <button type="submit">提交</button>
  </form>
</template>

<script setup>
import { ref } from 'vue'

const email = ref('')
const phone = ref('')
</script>

自定义错误消息:

<input 
  v-validate="{ 
    rules: 'required|email', 
    message: '请输入正确的邮箱地址' 
  }" 
  name="email" 
/>

<!-- 或者分别自定义 -->
<input 
  v-validate="{ 
    rules: 'required|email',
    message: {
      required: '邮箱必填',
      email: '邮箱格式不对'
    }
  }" 
  name="email" 
/>

方式二:使用规则辅助函数

<template>
  <input v-validate="emailRules" name="email" />
  <input v-validate="passwordRules" name="password" type="password" />
</template>

<script setup>
import { Rules } from '@yojack/vue-supervalidator'

// 预定义规则,一键使用
const emailRules = Rules.email('请输入正确的邮箱')
const passwordRules = Rules.strongPassword('密码强度不够')
</script>

方式三:Composition API(最灵活)

适合复杂表单,需要完全控制校验逻辑。

<template>
  <form @submit.prevent="handleSubmit">
    <div>
      <input v-model="formData.email" @blur="validateField('email')" />
      <span v-if="hasError('email')">{{ getFieldError('email') }}</span>
    </div>
    <div>
      <input v-model="formData.phone" @blur="validateField('phone')" />
      <span v-if="hasError('phone')">{{ getFieldError('phone') }}</span>
    </div>
    <button type="submit">提交</button>
  </form>
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import { useFormValidator } from '@yojack/vue-supervalidator'

const formData = reactive({
  email: '',
  phone: ''
})

const rules = {
  email: [
    { required: true, message: '请输入邮箱' },
    { email: true, message: '邮箱格式不正确' }
  ],
  phone: [
    { required: true, message: '请输入手机号' },
    { phone: true, message: '手机号格式不正确' }
  ]
}

const { 
  validate, 
  validateField, 
  hasError, 
  getFieldError 
} = useFormValidator(formData, rules)

const handleSubmit = async () => {
  const result = await validate()
  if (result.valid) {
    console.log('表单验证通过', formData)
    // 提交数据
  }
}
</script>

📚 规则分类

1️⃣ 基础校验 (16个)

{ required: true }                    // 必填
{ min: 10, max: 100 }                // 数值范围
{ minLength: 6, maxLength: 20 }      // 长度范围
{ length: 11 }                       // 固定长度
{ pattern: /^[A-Z]+$/ }              // 正则表达式
{ between: [10, 100] }               // 范围
{ lengthBetween: [6, 20] }           // 长度范围

// 条件必填
{ requiredIf: 'otherField' }         // 当其他字段有值时必填
{ requiredWith: 'field1' }           // 与字段关联
{ requiredWithAll: ['f1', 'f2'] }    // 多字段关联

2️⃣ 邮箱和通讯 (17个)

{ email: true }                      // 邮箱
{ emailStrict: true }                // 严格邮箱
{ phone: true }                      // 中国手机号
{ phoneChinaMobile: true }           // 中国移动
{ phoneChinaUnicom: true }           // 中国联通
{ phoneChinaTelecom: true }          // 中国电信
{ phoneUS: true }                    // 美国电话
{ phoneUK: true }                    // 英国电话
{ phoneJP: true }                    // 日本电话
{ phoneKR: true }                    // 韩国电话
{ phoneInternational: true }         // 国际格式
{ tel: true }                        // 座机
{ mobile: true }                     // 移动电话

3️⃣ 网络相关 (18个)

{ url: true }                        // URL
{ urlHttp: true }                    // HTTP/HTTPS
{ domain: true }                     // 域名
{ ip: true }                         // IP地址
{ ipv4: true }                       // IPv4
{ ipv6: true }                       // IPv6
{ port: true }                       // 端口号
{ mac: true }                        // MAC地址

4️⃣ 数字相关 (20个)

{ number: true }                     // 数字
{ integer: true }                    // 整数
{ float: true }                      // 浮点数
{ positive: true }                   // 正数
{ negative: true }                   // 负数
{ positiveInteger: true }            // 正整数
{ even: true }                       // 偶数
{ odd: true }                        // 奇数
{ percentage: true }                 // 百分比(0-100)
{ divisibleBy: 5 }                   // 能被5整除

5️⃣ 身份证件 (15个)

{ idCard: true }                     // 中国身份证(含校验码验证)
{ passport: true }                   // 护照
{ passportCN: true }                 // 中国护照
{ drivingLicense: true }             // 驾驶证
{ businessLicense: true }            // 营业执照
{ socialCreditCode: true }           // 统一社会信用代码

6️⃣ 银行和金融 (18个)

{ bankCard: true }                   // 银行卡(Luhn算法验证)
{ creditCard: true }                 // 信用卡
{ visa: true }                       // Visa卡
{ mastercard: true }                 // Mastercard
{ unionPay: true }                   // 银联卡
{ money: true }                      // 金额格式
{ stockCodeCN: true }                // 中国股票代码

7️⃣ 日期和时间 (26个)

{ date: true }                       // 日期
{ time: true }                       // 时间
{ dateTime: true }                   // 日期时间
{ timestamp: true }                  // Unix时间戳
{ dateAfter: '2024-01-01' }         // 晚于指定日期
{ dateBefore: '2024-12-31' }        // 早于指定日期
{ dateBetween: ['2024-01-01', '2024-12-31'] }  // 日期范围
{ birthday: true }                   // 生日
{ age: [18, 65] }                   // 年龄范围
{ futureDate: true }                 // 未来日期
{ pastDate: true }                   // 过去日期

8️⃣ 中文相关 (9个)

{ chinese: true }                    // 纯中文
{ chineseName: true }                // 中文姓名
{ chineseAndNumber: true }           // 中文+数字
{ noChinese: true }                  // 不含中文

9️⃣ 英文和字符 (14个)

{ alpha: true }                      // 纯字母
{ alphaNum: true }                   // 字母数字
{ lowercase: true }                  // 小写
{ uppercase: true }                  // 大写
{ camelCase: true }                  // 驼峰命名
{ snakeCase: true }                  // 蛇形命名
{ kebabCase: true }                  // 短横线命名

🔟 特殊格式 (27个)

{ username: true }                   // 用户名(4-16位)
{ password: true }                   // 密码(数字+字母)
{ strongPassword: true }             // 强密码(数字+字母+特殊字符)
{ hexColor: true }                   // 十六进制颜色
{ uuid: true }                       // UUID
{ base64: true }                     // Base64编码
{ md5: true }                        // MD5
{ sha256: true }                     // SHA256
{ jwt: true }                        // JWT Token

1️⃣1️⃣ 车辆相关 (6个)

{ licensePlate: true }               // 车牌号
{ licensePlateNewEnergy: true }      // 新能源车牌
{ vin: true }                        // 车架号

1️⃣2️⃣ 社交媒体 (11个)

{ qq: true }                         // QQ号
{ wechat: true }                     // 微信号
{ github: true }                     // GitHub用户名
{ twitter: true }                    // Twitter

1️⃣3️⃣ 比较验证 (8个)

{ same: 'password' }                 // 与password字段相同
{ different: 'oldPassword' }         // 与字段不同
{ gt: 'minValue' }                   // 大于指定字段
{ lt: 'maxValue' }                   // 小于指定字段
{ equals: 100 }                      // 等于某值

1️⃣4️⃣ 包含验证 (6个)

{ in: ['male', 'female'] }           // 在数组中
{ notIn: ['admin', 'root'] }         // 不在数组中
{ contains: 'keyword' }              // 包含字符串
{ startsWith: 'prefix_' }            // 以...开头
{ endsWith: '.com' }                 // 以...结尾

1️⃣5️⃣ 其他分类

  • 字符串验证 (17个): json, xml, html, notEmpty, wordCount 等
  • 邮编和地址 (10个): zipCode, zipCodeUS, latitude, longitude 等
  • 业务相关 (16个): studentId, invoiceNumber, isbn, trackingNumber 等
  • 安全相关 (4个): noSqlInjection, noXss, noScript, safeString
  • 数组和对象 (6个): arrayLength, arrayUnique, objectKeys 等
  • 文件相关 (18个): fileSize, imageFormat, imageWidth 等

总计:226+ 规则

🔧 API 文档

useFormValidator(formData, rules)

创建表单校验器的主要方法。

参数:

  • formData - 响应式的表单数据对象
  • rules - 校验规则配置对象

返回值:

{
  validate: () => Promise<ValidationResult>      // 校验所有字段
  validateField: (field: string) => Promise<boolean>  // 校验单个字段
  errors: Reactive<Record<string, string[]>>     // 错误信息对象
  validating: Ref<boolean>                       // 是否正在校验
  hasError: (field: string) => boolean           // 检查字段是否有错误
  getFieldError: (field: string) => string       // 获取字段第一个错误
  clearErrors: () => void                        // 清除所有错误
  clearFieldError: (field: string) => void       // 清除指定字段错误
  reset: () => void                              // 重置表单
  setFieldError: (field: string, errors: string | string[]) => void  // 设置字段错误
}

💡 使用示例

用户注册表单

const formData = reactive({
  username: '',
  email: '',
  phone: '',
  password: '',
  confirmPassword: ''
})

const rules = {
  username: [
    { required: true, message: '请输入用户名' },
    { minLength: 4, message: '用户名至少4个字符' },
    { maxLength: 16, message: '用户名最多16个字符' },
    { username: true, message: '用户名只能包含字母、数字、下划线' }
  ],
  email: [
    { required: true, message: '请输入邮箱' },
    { email: true, message: '邮箱格式不正确' }
  ],
  phone: [
    { required: true, message: '请输入手机号' },
    { phone: true, message: '手机号格式不正确' }
  ],
  password: [
    { required: true, message: '请输入密码' },
    { minLength: 8, message: '密码至少8个字符' },
    { strongPassword: true, message: '密码必须包含数字、字母和特殊字符' }
  ],
  confirmPassword: [
    { required: true, message: '请确认密码' },
    { same: 'password', message: '两次密码输入不一致' }
  ]
}

const { validate, validateField, hasError, getFieldError } = useFormValidator(formData, rules)

实名认证表单

const rules = {
  realName: [
    { required: true, message: '请输入姓名' },
    { chinese: true, message: '姓名只能是中文' },
    { minLength: 2, maxLength: 10 }
  ],
  idCard: [
    { required: true, message: '请输入身份证号' },
    { idCard: true, message: '身份证号格式不正确' }  // 含校验码验证
  ],
  bankCard: [
    { required: true, message: '请输入银行卡号' },
    { bankCard: true, message: '银行卡号格式不正确' }  // Luhn算法验证
  ]
}

异步校验

const rules = {
  username: [
    { required: true, message: '请输入用户名' },
    {
      asyncValidator: async (value) => {
        const response = await fetch(`/api/check-username?name=${value}`)
        const data = await response.json()
        return data.available
      },
      message: '用户名已被占用'
    }
  ]
}

条件必填

const rules = {
  companyName: [
    { requiredIf: 'userType' }  // 当 userType 有值时必填
  ],
  businessLicense: [
    { requiredWith: 'companyName' }  // 当 companyName 有值时必填
  ]
}

🎯 完整规则列表

基础校验

required requiredIf requiredUnless requiredWith requiredWithAll requiredWithout requiredWithoutAll min max between minLength maxLength length lengthBetween pattern notPattern

邮箱和通讯

email emailStrict emails phone phoneLoose phoneChinaMobile phoneChinaUnicom phoneChinaTelecom phoneUS phoneUK phoneJP phoneKR phoneInternational tel telWithArea mobile fax

网络相关

url urlHttp urlFtp urlWebsocket domain domainStrict subdomain ip ipv4 ipv4WithMask ipv4Private ipv4Public ipv6 ipv6Compressed port portRange mac

数字相关

number numeric integer float decimal decimalBetween positive negative nonNegative nonPositive positiveInteger negativeInteger even odd divisibleBy percentage percentageStrict scientificNotation binary octal

身份证件

idCard idCard15 idCard18 passport passportCN passportUS passportUK drivingLicense militaryId hkMacaoPass taiwanPass businessLicense organizationCode socialCreditCode taxId

银行和金融

bankCard bankCardCN creditCard debitCard visa mastercard amex unionPay jcb iban swift bic currency money moneyPositive stockCode stockCodeCN stockCodeUS

邮编和地址

zipCode zipCodeUS zipCodeUK zipCodeJP postCode address addressCN latitude longitude coordinates

日期和时间

date dateYMD dateMDY dateDMY dateISO time time12 time24 timeWithSeconds dateTime dateTimeISO timestamp timestampMs dateAfter dateBefore dateBetween dateEquals timeAfter timeBefore birthday age futureDate pastDate today weekday weekend

中文相关

chinese chineseAndNumber chineseAndLetter chineseAndSymbol noChinese chineseName chineseNameWithDot simplifiedChinese traditionalChinese

英文和字符

alpha alphaNum alphaDash alphaSpace alphaNumSpace lowercase uppercase capitalizeFirst camelCase snakeCase kebabCase ascii asciiPrintable unicode

特殊格式

username usernameStrict password strongPassword weakPassword passwordCustom hex hexColor color rgb rgba hsl hsla base64 base64Image base64Url md5 sha1 sha256 sha512 uuid uuidV1 uuidV3 uuidV4 uuidV5 jwt

车辆相关

licensePlate licensePlateCN licensePlateNewEnergy vin vinStrict engineNumber

社交媒体

qq qqStrict wechat wechatStrict weibo douyin twitter facebook instagram linkedin github

比较验证

same different gt gte lt lte equals notEquals

包含验证

in notIn contains notContains startsWith endsWith

字符串验证

json jsonObject jsonArray xml html notEmpty notBlank noWhitespace noLeadingWhitespace noTrailingWhitespace wordCount wordCountMin wordCountMax wordCountBetween charCount charCountMin charCountMax

数组和对象

arrayLength arrayMinLength arrayMaxLength arrayUnique objectKeys objectKeysOptional

业务相关

studentId teacherId classNumber medicalRecordNumber prescriptionNumber trackingNumber trackingNumberSF trackingNumberYTO trackingNumberZTO trackingNumberYD invoiceNumber invoiceCode isbn isbn10 isbn13 issn

安全相关

noSqlInjection noXss noScript safeString

文件相关

fileExtension fileSize fileSizeMin fileSizeMax fileSizeBetween imageFormat videoFormat audioFormat documentFormat archiveFormat imageWidth imageHeight imageMinWidth imageMinHeight imageMaxWidth imageMaxHeight imageRatio mimeType

🌟 高级特性

自定义校验

{
  custom: (value, formData) => {
    return value.length > 0 && value !== formData.username
  },
  message: '自定义校验失败'
}

异步校验

{
  asyncValidator: async (value, formData) => {
    const response = await fetch(`/api/validate?value=${value}`)
    const data = await response.json()
    return data.valid
  },
  message: '校验失败'
}

值转换

{
  trim: true,              // 自动去除首尾空格
  toLowerCase: true,       // 转小写
  toUpperCase: true,       // 转大写
  transform: (value) => {  // 自定义转换
    return value.replace(/\s+/g, '')
  }
}

自定义错误消息

// 单个规则
{ email: true, message: '请输入正确的邮箱地址' }

// 占位符
{ min: 10, message: '值不能小于 {min}' }
{ between: [10, 100], message: '值必须在 {min} 到 {max} 之间' }

🔐 专业特性

身份证校验码验证

使用加权因子算法验证18位身份证号的校验码:

{ idCard: true }  // 自动验证校验码是否正确

银行卡Luhn算法

标准的Luhn算法验证银行卡号:

{ bankCard: true }  // 自动使用Luhn算法验证

车牌号识别

支持普通车牌和新能源车牌:

{ licensePlate: true }           // 普通车牌:京A12345
{ licensePlateNewEnergy: true }  // 新能源:京AD1234F

📖 完整示例

<template>
  <div class="form-container">
    <form @submit.prevent="handleSubmit">
      <!-- 用户名 -->
      <div class="form-group">
        <label>用户名 *</label>
        <input
          v-model="formData.username"
          @blur="validateField('username')"
          :class="{ error: hasError('username') }"
        />
        <span class="error-msg">{{ getFieldError('username') }}</span>
      </div>

      <!-- 邮箱 -->
      <div class="form-group">
        <label>邮箱 *</label>
        <input
          v-model="formData.email"
          @blur="validateField('email')"
          :class="{ error: hasError('email') }"
        />
        <span class="error-msg">{{ getFieldError('email') }}</span>
      </div>

      <!-- 手机号 -->
      <div class="form-group">
        <label>手机号 *</label>
        <input
          v-model="formData.phone"
          @blur="validateField('phone')"
          :class="{ error: hasError('phone') }"
        />
        <span class="error-msg">{{ getFieldError('phone') }}</span>
      </div>

      <!-- 密码 -->
      <div class="form-group">
        <label>密码 *</label>
        <input
          v-model="formData.password"
          type="password"
          @blur="validateField('password')"
          :class="{ error: hasError('password') }"
        />
        <span class="error-msg">{{ getFieldError('password') }}</span>
      </div>

      <!-- 确认密码 -->
      <div class="form-group">
        <label>确认密码 *</label>
        <input
          v-model="formData.confirmPassword"
          type="password"
          @blur="validateField('confirmPassword')"
          :class="{ error: hasError('confirmPassword') }"
        />
        <span class="error-msg">{{ getFieldError('confirmPassword') }}</span>
      </div>

      <button type="submit" :disabled="validating">
        {{ validating ? '提交中...' : '提交' }}
      </button>
    </form>
  </div>
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import { useFormValidator } from '@yojack/vue-supervalidator'

const formData = reactive({
  username: '',
  email: '',
  phone: '',
  password: '',
  confirmPassword: ''
})

const rules = {
  username: [
    { required: true, message: '请输入用户名' },
    { minLength: 4, maxLength: 16 },
    { username: true }
  ],
  email: [
    { required: true, message: '请输入邮箱' },
    { email: true }
  ],
  phone: [
    { required: true, message: '请输入手机号' },
    { phone: true }
  ],
  password: [
    { required: true, message: '请输入密码' },
    { minLength: 8 },
    { strongPassword: true }
  ],
  confirmPassword: [
    { required: true, message: '请确认密码' },
    { same: 'password', message: '两次密码不一致' }
  ]
}

const {
  validate,
  validateField,
  validating,
  hasError,
  getFieldError,
  clearErrors
} = useFormValidator(formData, rules)

const handleSubmit = async () => {
  const result = await validate()
  
  if (result.valid) {
    console.log('表单验证通过', formData)
    // 提交表单数据到服务器
  } else {
    console.log('表单验证失败', result.errors)
  }
}
</script>

<style scoped>
.form-group {
  margin-bottom: 15px;
}

.form-group label {
  display: block;
  margin-bottom: 5px;
  font-weight: bold;
}

.form-group input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.form-group input.error {
  border-color: #f56c6c;
}

.error-msg {
  color: #f56c6c;
  font-size: 12px;
  margin-top: 5px;
  display: block;
}

button {
  padding: 10px 20px;
  background-color: #409eff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:disabled {
  background-color: #a0cfff;
  cursor: not-allowed;
}
</style>

🌍 多语言支持

自定义错误消息

// 单个规则自定义
{ email: true, message: '请输入正确的邮箱地址' }

// 全局自定义(如果使用插件模式)
app.use(FormValidatorPlugin, {
  messages: {
    required: '该字段必填',
    email: '邮箱格式错误'
  }
})

🔗 相关链接

📄 License

MIT License © 2024 Yojack

🤝 贡献

欢迎提交 Issue 和 Pull Request!


如果这个项目对你有帮助,欢迎给个 ⭐ Star!