/** * 表单验证 * 默认导出为验证类的实例: * 所以不要存在并行验证的情况 * 如果需要并行验证 * 请自行实例化验证类 * * Validation().data($data).rules({ * '字段名': { * title: '字段中文名称', * msg: '验证错误提示语【可选】', * rules: [ * { * required: true, * msg: '该条规则验证错误提示语【可选】' // 注:优先级高于msg * } * ], * // 自定义验证【可选】 * validator(value) { * return false // 验证通过 * } * }, * field1: { * title: '字段1', * msg: '字段1必须符合规则', * rules: [ * { required: true, msg: '必填' }, * { isIP: true, msg: '是否是正确的ip' }, * { isURL: true, msg: '是否是正确的URL' }, * { isPostcode: true, msg: '是否是正确的邮政编码' }, * { isCellphone: true, msg: '是否是正确的手机号' }, * { isfixedphone: true, msg: '是否是正确的固定电话' }, * { isEmail: true, msg: '是否是正确的邮箱地址' }, * { isAvaiableLength: {min: 0, max: 100}, msg: '字符串长度是否在某个范围' }, * { isString: true, msg: '是否字符串' }, * { isNumber: true, msg: '是否是数字' }, * { isObj: true, msg: '是否是对象' }, * { isArray: true, msg: '是否是数组' }, * { isDate: true, msg: '是否是日期' }, * { isBoolean: true, msg: '是否是boolean' }, * { isFunction: true, msg: '是否是函数' }, * { isNull: true, msg: '是否是null' }, * { isUndefined: true, msg: '是否是undefined' }, * { isCardID: true, msg: '是否是正确的身份证号' }, * { isLetterOnly: true, msg: '只能是字母' }, * { isNumberOnly: true, msg: '只能是数字' }, * { isLetterOrNumberOnly: true, msg: '只能是数字字母' }, * { min: true, msg: '不能小于' }, * { max: true, msg: '不能大于' }, * { range: true, msg: '在某个范围内' }, * { regex: true, msg: '自定义验证函数' }, * ], * validator: function(value) { * return false;// 验证通过 * } * } *}).check(); * */ export class Verification { constructor() { // 初始化验证规则集合 this._initValidators() // 验证类错误提示语 this.lang = { _valida_required_: '不能为空', _valida_isIP: '不是一个正确的IP', _valida_isURL: '不是一个正确的URL', _valida_isPostcode: '不是一个正确的邮政编码', _valida_isCellphone: '不是一个正确的手机号', _valida_isfixedphone: '不是一个正确的座机号', _valida_isEmail: '不是一个正确邮箱地址', _valida_isAvaiableLength: '', _valida_isString: '', _valida_isNumber: '', _valida_isObj: '', _valida_isArray: '', _valida_isDate: '', _valida_isBoolean: '', _valida_isFunction: '', _valida_isNull: '', _valida_isUndefined: '', _valida_isCardID: '', _valida_isLetterOnly: '', _valida_isNumberOnly: '', _valida_isLetterOrNumberOnly: '', _valida_min: '', _valida_max: '', _valida_range: '', _valida_regex: '' } } /** * 初始化实例数据 */ _initData() { this.errorCount = 0 this.errorList = {} } /** * 设置待验证的数据 * @param {*} d 待验证的数据 * @returns this用于链式调用 */ data(d = {}) { this._initData() this.waitCheckData = d return this } /** * 验证规则 * @param {object} r 设置验证数据中每个字段使用的规则集合 * @returns this用于链式调用 */ rules(r = {}) { this.waitUseRules = r return this } /** * 开始验证 * @param {number} type 验证类型 1 - 只要遇到第一个不符合的就返回结果 ;2 - 验证全部字段,返回所有不符合规范的字段 * @returns {(boolean|string|object)} 返回false验证成功,返回字符串(错误提示语)验证失败,返回对象(错误集合)验证失败 */ check(type = 1) { for (let field in this.waitUseRules) { const errMsg = this.checkFieldRule( this.waitCheckData[field], // 字段值 value this.waitUseRules[field], // 验证规则集合 field // 字段名 ) if (errMsg) { if (type === 1) { return `${this.waitUseRules[field].title}: ${errMsg}` } } } if (this.errorCount === 0) { return false } return this._getError() } /** * 获取错误集合 * @returns {object} 错误对象 */ _getError() { return this.errorList } /** * 设置错误 * @param {*} title 字段中文提示 * @param {*} field 字段名 * @param {*} errMsg 错误提示语 */ _setEorror(title, field, errMsg) { if (!this.errorList[field]) { this.errorList[field] = { title: title, field: field, msg: errMsg } this.errorCount += 1 } else { this.errorList[field].msg += ',' + errMsg } } /** * 验证某个指定字段的规则 * @param {*} value 字段值 * @param {*} waitUseRules 字段的验证规则集合 * @param {string} field 字段名称 * @returns {(boolean|string)} false:验证通过 */ checkFieldRule(value, waitUseRules, field) { let _rules = [] // 验证规则数组 let errMsg = false if (waitUseRules.rules) { if ( Object.prototype.toString.call(waitUseRules.rules).slice(8, -1) === 'Array' ) { _rules = waitUseRules.rules } else { _rules = [waitUseRules.rules] } for (let i = 0, leng = _rules.length; i < leng; i++) { if (_rules[i]) { errMsg = this._doCheck(value, _rules[i], field) // _rules[i] = { isIP: true, msg: '是否是正确的ip111' } if (errMsg) { errMsg = _rules[i].msg || (waitUseRules.msg || errMsg) this._setEorror(waitUseRules.title, field, errMsg) break } } } } if (!errMsg) { // 自定义验证规则 if (waitUseRules.validator) { errMsg = waitUseRules.validator.call(this, value) } if (errMsg) { this._setEorror(waitUseRules.title, field, errMsg) } } return errMsg } /** * 执行验证 * @param {*} value 字段值 * @param {*} rule 验证规则名称 * @param {string} field 字段名 * @returns {(boolean|string)} false:验证通过 */ _doCheck(value, rule, field) { let errMsg = false for (let method in rule) { // { isIP: true, msg: '是否是正确的ip111' } if (method !== 'msg') { // 判断方法是否存在 if (this._methodIsEmpty(method)) { let args = rule[method] // 验证方法所需要的参数 const _errMsg = this.validators[method](value, args) if (_errMsg) { errMsg = _errMsg break } } } } return errMsg } /** * 判断验证规则是否存在 * @param {*} value 待验证方法名 * @returns {boolean} true:存在;false:不存在 */ _methodIsEmpty(value) { if (this.validators[value]) { return true } return false } /** * 判断是否为空 * @param {*} value */ _isEmpty(value) { if ( value === '' || value === undefined || value === null || value === 'null' || value === 'undefined' ) { return true } return false } /** * 初始化自带验证规则 */ _initValidators() { let that = this that.validators = { /** * 验证必填 * @param {*} value * @param {*} args * @returns false:验证通过 */ required(value, args) { let res = false if (Object.prototype.toString.call(value).slice(8, -1) === 'String') { res = value.replace(/\s+/g, '').length > 0 } else if ( Object.prototype.toString.call(value).slice(8, -1) === 'Array' ) { // 只验证数组 类型 res = value.length > 0 } else if (!that._isEmpty(value)) { res = true } return !res ? that.lang['_form_valida_required_'] : false }, /** * * @descrition:判断是否是合理的IP地址 * @param:value->待验证的IP地址 * @returns {(boolean|string)} false:验证通过 * */ isIP(value, args) { let res = false var pattern = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ res = pattern.test(value) return !res ? that.lang['_valida_isIP'] : false }, /** * @descrition:判断输入的参数是否是个合格的URL,由于url的灵活性和多样性,一下代码并不能测试所有的url都是合法的(PS:该正则无法通配所有的URL,请慎用) * @param:value->待判断的url参数 * @returns {(boolean|string)} false:验证通过 **/ isURL(value, args) { let res = false var strRegex = '^((https|http|ftp|rtsp|mms)?://)' + "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" + // ftp的user@ '(([0-9]{1,3}.){3}[0-9]{1,3}' + // IP形式的URL- 199.194.52.184 '|' + // 允许IP和DOMAIN(域名) "([0-9a-z_!~*'()-]+.)*" + // 域名- www. '([0-9a-z][0-9a-z-]{0,61})?[0-9a-z].' + // 二级域名 '[a-z]{2,6})' + // first level domain- .com or .museum '(:[0-9]{1,4})?' + // 端口- :80 '((/?)|' + "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$" var pattern = new RegExp(strRegex) res = pattern.test(value) return !res ? that.lang['_valida_isIP'] : false }, /** * * @descrition:判断输入的参数是否是国内合法的邮编地址(ps:国内不包含国外的邮编) * @link: http://www.youbianku.com/%E9%A6%96%E9%A1%B5 * @param: value 为待验证的邮编号码 * @returns {(boolean|string)} false:验证通过 * */ isPostcode(value, args) { let res = false var pattern = /^[0-8]\d{5}$/ res = pattern.test(value) return !res ? that.lang['_valida_isPostcode'] : false }, /** * * @descrition:判断输入的参数是否是个合格的手机号码,不能判断号码的有效性,有效性可以通过运营商确定。 * @param:value ->待判断的手机号码 * @returns {(boolean|string)} false:验证通过 * */ isCellphone(value, args) { let res = false /** *@descrition:手机号码段规则 * 13段:130、131、132、133、134、135、136、137、138、139 * 14段:140、141、142、143、144、145、146、147、148、149 * 15段:150、151、152、153、154、155、156、157、158、159 * 16段:160、161、162、163、164、165、166、167、168、169 * 17段:170、171、172、173、174、175、176、177、178、179 * 18段:180、181、182、183、184、185、186、187、188、189 * 19段:190、191、192、193、194、195、196、197、198、199 */ var pattern = /^[1][3,4,5,6,7,8,9][0-9]\d{8}$/ res = pattern.test(value) return !res ? that.lang['_valida_isCellphone'] : false }, /** * @descrition:判断输入的参数是否是个合格的固定电话号码。 * @param:value->待验证的固定电话号码。 * @returns {(boolean|string)} false:验证通过 * **/ isfixedphone(value, args) { let res = false /** * * @desctition:规则->区号3-4位,号码7-8位,可以有分机号,分机号为3-4为,格式如下:"0775-85333333-123" * */ var pattern = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/ res = pattern.test(value) return !res ? that.lang['_valida_isfixedphone'] : false }, /** * * @descrition:判断输入的参数是否是个合格标准的邮箱,并不能判断是否有效,有效只能通过邮箱提供商确定。 * @param:value ->待验证的参数。 * @returns {(boolean|string)} false:验证通过 * */ isEmail(value, args) { let res = false /** * @descrition:邮箱规则 * 1.邮箱以a-z、A-Z、0-9开头,最小长度为1. * 2.如果左侧部分包含-、_、.则这些特殊符号的前面必须包一位数字或字母。 * 3.@符号是必填项 * 4.右则部分可分为两部分,第一部分为邮件提供商域名地址,第二部分为域名后缀,现已知的最短为2位。最长的为6为。 * 5.邮件提供商域可以包含特殊字符-、_、. */ var pattern = /^([a-zA-Z0-9]+[-_.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[-_.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,6}$/ res = pattern.test(value) return !res ? that.lang['_valida_isEmail'] : false }, /** * 判断传入的参数的长度是否在给定的有效范围内 * @param->value : 传入的参数,参数可以为任何类型。 * @param {*} args 验证需要的参数 * @returns {(boolean|string)} false:验证通过 * */ isAvaiableLength(value, args = { min: 0, max: 0 }) { let res = false if (that._isEmpty(value)) { res = false } else { if (value.length >= args.min && value.length <= args.max) { res = true } } return !res ? that.lang['_valida_isAvaiableLength'] : false }, /** * 判断是否字符串 * @param->value : 传入的参数,参数可以为任何类型。 * @returns {(boolean|string)} false:验证通过 */ isString(value, args) { let res = false // 是否字符串 if (Object.prototype.toString.call(value).slice(8, -1) === 'String') { res = true } return !res ? that.lang['_valida_isString'] : false }, /** * * @descrition : 该函数的功能是判断转入的参数是否为数字类型。 * @param->value : 传入的参数,参数可以为任何类型。 * @returns {(boolean|string)} false:验证通过 * */ isNumber(value, args) { let res = false // 是否数字 if (Object.prototype.toString.call(value).slice(8, -1) === 'Number') { res = true } return !res ? that.lang['_valida_isNumber'] : false }, isObj(value, args) { // 是否对象 let res = false if (Object.prototype.toString.call(value).slice(8, -1) === 'Object') { res = true } return !res ? that.lang['_valida_isObj'] : false }, isArray(value, args) { // 是否数组 let res = false if (Object.prototype.toString.call(value).slice(8, -1) === 'Array') { res = true } return !res ? that.lang['_valida_isArray'] : false }, isDate(value, args) { // 是否时间 let res = false if (Object.prototype.toString.call(value).slice(8, -1) === 'Date') { res = true } return !res ? that.lang['_valida_isDate'] : false }, isBoolean(value, args) { // 是否boolean let res = false if (Object.prototype.toString.call(value).slice(8, -1) === 'Boolean') { res = true } return !res ? that.lang['_valida_isBoolean'] : false }, isFunction(value, args) { // 是否函数 let res = false if (Object.prototype.toString.call(value).slice(8, -1) === 'Function') { res = true } return !res ? that.lang['_valida_isFunction'] : false }, isNull(value, args) { // 是否为null let res = false if (Object.prototype.toString.call(value).slice(8, -1) === 'Null') { res = true } return !res ? that.lang['_valida_isNull'] : false }, isUndefined(value, args) { // 是否undefined let res = false if ( Object.prototype.toString.call(value).slice(8, -1) === 'Undefined' ) { res = true } return !res ? that.lang['_valida_isUndefined'] : false }, isCardID(value, args) { let res = true if (!/(^\d{15}$)|(^\d{17}(\d|X|x)$)/.test(value)) { res = false } // 身份证城市 var aCity = { 11: '北京', 12: '天津', 13: '河北', 14: '山西', 15: '内蒙古', 21: '辽宁', 22: '吉林', 23: '黑龙江', 31: '上海', 32: '江苏', 33: '浙江', 34: '安徽', 35: '福建', 36: '江西', 37: '山东', 41: '河南', 42: '湖北', 43: '湖南', 44: '广东', 45: '广西', 46: '海南', 50: '重庆', 51: '四川', 52: '贵州', 53: '云南', 54: '西藏', 61: '陕西', 62: '甘肃', 63: '青海', 64: '宁夏', 65: '新疆', 71: '台湾', 81: '香港', 82: '澳门', 91: '国外' } if (!aCity[parseInt(value.substr(0, 2))]) { res = false } // 出生日期验证 var sBirthday = ( value.substr(6, 4) + '-' + Number(value.substr(10, 2)) + '-' + Number(value.substr(12, 2)) ).replace(/-/g, '/') var d = new Date(sBirthday) if ( sBirthday !== d.getFullYear() + '/' + (d.getMonth() + 1) + '/' + d.getDate() ) { res = false } // 身份证号码校验 var sum = 0 var weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] var codes = '10X98765432' for (var i = 0; i < value.length - 1; i++) { sum += value[i] * weights[i] } var last = codes[sum % 11] // 计算出来的最后一位身份证号码 if (value[value.length - 1] !== last) { res = false } return !res ? that.lang['_valida_isCardID'] : false }, // 验证只能是字母 isLetterOnly(value) { let res = false var pattern = /^[a-zA-Z]*$/ res = pattern.test(value) if (value === '') { res = true } return !res ? that.lang['_valida_isLetterOnly'] : false }, // 验证只能为数字 isNumberOnly(value) { let res = false var pattern = /^[0-9]+$/ res = pattern.test(value) if (value === '') { res = true } return !res ? that.lang['_valida_isNumberOnly'] : false }, // 验证只能是字母和数字 isLetterOrNumberOnly(value) { let res = false var pattern = /^[0-9a-zA-Z]*$/ res = pattern.test(value) if (value === '') { res = true } return !res ? that.lang['_valida_isLetterOrNumberOnly'] : false }, // 最小值 min(value, args) { var reg = /^[0-9]+$/ if (value !== '' && !reg.test(value)) { return that.lang['_valida_min'] } if (args.min !== '' && !reg.test(args.min)) { return that.lang['_valida_min'] } if (parseFloat(value) < parseFloat(args.min)) { return that.lang['_valida_min'] } return false }, // 最大值 max(value, args) { var reg = /^[0-9]+$/ if (value !== '' && !reg.test(value)) { return that.lang['_valida_max'] } if (args.max !== '' && !reg.test(args.max)) { return that.lang['_valida_max'] } if (parseFloat(value) > parseFloat(args.max)) { return that.lang['_valida_max'] } return false }, // 某个范围 range(value, args = { min: 0, max: 0 }) { var reg = /^[0-9]+$/ if (value !== '' && !reg.test(value)) { return that.lang['_valida_range'] } if (args.max !== '' && !reg.test(args.max)) { return that.lang['_valida_range'] } if (args.min !== '' && !reg.test(args.min)) { return that.lang['_valida_range'] } if ( parseFloat(args.min) > parseFloat(value) || parseFloat(value) > parseFloat(args.max) ) { return that.lang['_valida_range'] } return false }, regex(value, reg) { let res = false if (reg && !reg.test(value)) { res = reg.test(value) } return !res ? that.lang['_valida_regex'] : false } } } }