vue-supervalidator
Version:
🚀 The most powerful Vue 3 form validation library with 226+ built-in rules
817 lines (661 loc) • 24.1 kB
Markdown
# Vue SuperValidator
> 🚀 The most powerful Vue 3 form validation library with 226+ built-in rules
一个功能强大、使用超简单的 Vue 3 表单校验插件。
[](https://www.npmjs.com/package/vue-supervalidator)
[](https://www.npmjs.com/package/vue-supervalidator)
[](https://github.com/Yojack/vue-supervalidator/blob/main/LICENSE)
## 🌟 为什么选择 Vue SuperValidator?
```vue
<!-- 只需一行代码,错误信息自动显示! -->
<input v-validate="'required|email'" name="email" />
```
- 🎯 **226+ 内置规则** - 包含身份证、银行卡、车牌号等专业验证
- ⚡ **超级简单** - 使用指令,错误信息自动显示,无需额外代码
- 🔐 **专业算法** - 身份证校验码、银行卡 Luhn 算法、车牌识别
- 🌍 **国际化** - 支持中国、美国、英国、日本、韩国等多国格式
- 💪 **TypeScript** - 100% TypeScript,完整类型支持
- 🎨 **三种使用方式** - 指令、辅助函数、Composition API,满足所有场景
## 📋 目录
- [为什么选择](#为什么选择-vue-supervalidator)
- [安装](#安装)
- [快速开始](#快速开始)
- [规则分类](#规则分类)
- [API文档](#api-文档)
- [完整规则列表](#完整规则列表)
- [许可证](#许可证)
## 📦 安装
```bash
npm install vue-supervalidator
```
## 🚀 快速开始
本插件提供**三种使用方式**,从简单到复杂,满足不同场景需求。
### 方式一:自定义指令(最简单)⭐ 推荐
**特点:错误信息自动显示,无需额外代码!**
```vue
<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>
```
**自定义错误消息:**
```vue
<input
v-validate="{
rules: 'required|email',
message: '请输入正确的邮箱地址'
}"
name="email"
/>
<!-- 或者分别自定义 -->
<input
v-validate="{
rules: 'required|email',
message: {
required: '邮箱必填',
email: '邮箱格式不对'
}
}"
name="email"
/>
```
### 方式二:使用规则辅助函数
```vue
<template>
<input v-validate="emailRules" name="email" />
<input v-validate="passwordRules" name="password" type="password" />
</template>
<script setup>
import { Rules } from 'vue-supervalidator'
// 预定义规则,一键使用
const emailRules = Rules.email('请输入正确的邮箱')
const passwordRules = Rules.strongPassword('密码强度不够')
</script>
```
### 方式三:Composition API(最灵活)
**适合复杂表单,需要完全控制校验逻辑。**
```vue
<template>
<form .prevent="handleSubmit">
<div>
<input v-model="formData.email" ="validateField('email')" />
<span v-if="hasError('email')">{{ getFieldError('email') }}</span>
</div>
<div>
<input v-model="formData.phone" ="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 '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个)
```typescript
{ 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个)
```typescript
{ 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个)
```typescript
{ 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个)
```typescript
{ 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个)
```typescript
{ idCard: true } // 中国身份证(含校验码验证)
{ passport: true } // 护照
{ passportCN: true } // 中国护照
{ drivingLicense: true } // 驾驶证
{ businessLicense: true } // 营业执照
{ socialCreditCode: true } // 统一社会信用代码
```
### 6️⃣ 银行和金融 (18个)
```typescript
{ bankCard: true } // 银行卡(Luhn算法验证)
{ creditCard: true } // 信用卡
{ visa: true } // Visa卡
{ mastercard: true } // Mastercard
{ unionPay: true } // 银联卡
{ money: true } // 金额格式
{ stockCodeCN: true } // 中国股票代码
```
### 7️⃣ 日期和时间 (26个)
```typescript
{ 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个)
```typescript
{ chinese: true } // 纯中文
{ chineseName: true } // 中文姓名
{ chineseAndNumber: true } // 中文+数字
{ noChinese: true } // 不含中文
```
### 9️⃣ 英文和字符 (14个)
```typescript
{ alpha: true } // 纯字母
{ alphaNum: true } // 字母数字
{ lowercase: true } // 小写
{ uppercase: true } // 大写
{ camelCase: true } // 驼峰命名
{ snakeCase: true } // 蛇形命名
{ kebabCase: true } // 短横线命名
```
### 🔟 特殊格式 (27个)
```typescript
{ 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个)
```typescript
{ licensePlate: true } // 车牌号
{ licensePlateNewEnergy: true } // 新能源车牌
{ vin: true } // 车架号
```
### 1️⃣2️⃣ 社交媒体 (11个)
```typescript
{ qq: true } // QQ号
{ wechat: true } // 微信号
{ github: true } // GitHub用户名
{ twitter: true } // Twitter
```
### 1️⃣3️⃣ 比较验证 (8个)
```typescript
{ same: 'password' } // 与password字段相同
{ different: 'oldPassword' } // 与字段不同
{ gt: 'minValue' } // 大于指定字段
{ lt: 'maxValue' } // 小于指定字段
{ equals: 100 } // 等于某值
```
### 1️⃣4️⃣ 包含验证 (6个)
```typescript
{ 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` - 校验规则配置对象
**返回值:**
```typescript
{
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 // 设置字段错误
}
```
## 💡 使用示例
### 用户注册表单
```typescript
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)
```
### 实名认证表单
```typescript
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算法验证
]
}
```
### 异步校验
```typescript
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: '用户名已被占用'
}
]
}
```
### 条件必填
```typescript
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`
## 🌟 高级特性
### 自定义校验
```typescript
{
custom: (value, formData) => {
return value.length > 0 && value !== formData.username
},
message: '自定义校验失败'
}
```
### 异步校验
```typescript
{
asyncValidator: async (value, formData) => {
const response = await fetch(`/api/validate?value=${value}`)
const data = await response.json()
return data.valid
},
message: '校验失败'
}
```
### 值转换
```typescript
{
trim: true, // 自动去除首尾空格
toLowerCase: true, // 转小写
toUpperCase: true, // 转大写
transform: (value) => { // 自定义转换
return value.replace(/\s+/g, '')
}
}
```
### 自定义错误消息
```typescript
// 单个规则
{ email: true, message: '请输入正确的邮箱地址' }
// 占位符
{ min: 10, message: '值不能小于 {min}' }
{ between: [10, 100], message: '值必须在 {min} 到 {max} 之间' }
```
## 🔐 专业特性
### 身份证校验码验证
使用加权因子算法验证18位身份证号的校验码:
```typescript
{ idCard: true } // 自动验证校验码是否正确
```
### 银行卡Luhn算法
标准的Luhn算法验证银行卡号:
```typescript
{ bankCard: true } // 自动使用Luhn算法验证
```
### 车牌号识别
支持普通车牌和新能源车牌:
```typescript
{ licensePlate: true } // 普通车牌:京A12345
{ licensePlateNewEnergy: true } // 新能源:京AD1234F
```
## 📖 完整示例
```vue
<template>
<div class="form-container">
<form .prevent="handleSubmit">
<!-- 用户名 -->
<div class="form-group">
<label>用户名 *</label>
<input
v-model="formData.username"
="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"
="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"
="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"
="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"
="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 '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>
```
## 🌍 多语言支持
### 自定义错误消息
```typescript
// 单个规则自定义
{ email: true, message: '请输入正确的邮箱地址' }
// 全局自定义(如果使用插件模式)
app.use(FormValidatorPlugin, {
messages: {
required: '该字段必填',
email: '邮箱格式错误'
}
})
```
## 🔗 相关链接
- [CHANGELOG](./CHANGELOG.md) - 版本更新记录
- [NPM Package](https://www.npmjs.com/package/vue-supervalidator)
- [GitHub](https://github.com/Yojack/vue-supervalidator)
## 📄 License
MIT License © 2024 Yojack
## 🤝 贡献
欢迎提交 Issue 和 Pull Request!
---
**如果这个项目对你有帮助,欢迎给个 ⭐ Star!**