UNPKG

vue-supervalidator

Version:

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

817 lines (661 loc) 24.1 kB
# Vue SuperValidator > 🚀 The most powerful Vue 3 form validation library with 226+ built-in rules 一个功能强大使用超简单的 Vue 3 表单校验插件 [![NPM Version](https://img.shields.io/npm/v/vue-supervalidator.svg)](https://www.npmjs.com/package/vue-supervalidator) [![NPM Downloads](https://img.shields.io/npm/dm/vue-supervalidator.svg)](https://www.npmjs.com/package/vue-supervalidator) [![License](https://img.shields.io/npm/l/vue-supervalidator.svg)](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 @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 '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 @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 '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 ## 🤝 贡献 欢迎提交 IssuePull Request! --- **如果这个项目对你有帮助,欢迎给个 Star!**