async-validator 源码学习笔记(五):Schema
系列文章:
1、async-validator 源码学习(一):文档翻译
2、async-validator 源码学习笔记(二):目录结构
3、async-validator 源码学习笔记(三):rule
4、async-validator 源码学习笔记(四):validator
Schema 是 async-validator 库的标准使用方式,使用 class 类的形式和构造函数方式进行定义的。
一、Schema 类使用方式
在官方文档中 Schema 的使用方式有如下几步:
- 从 async-validator 中引入 Schema 类。
- 定义校验规则 descriptor 。
- 使用 new 创建一个 Schema 的实例。
- 调用实例的 validate 方法。
使用 demo:
//引入 import Schema from 'async-validator' // 定义校验规则 const descriptor = { username: { type: 'string', required: true, validator(rule, value) { return value != '' }, message: '用户名不能为空', } } //实例化 const validator = new Schema(descriptor ) //开始校验 validator.validate({ username:'需要验证的值' },(error, fields) => { if(errors){ //校验失败 return handleError( errors, fields ) } //校验成功 }) // 或者 promise 用法 validator.validate({ username:'需要验证的值' }) .then(res => { //校验成功 }) .catch(({errors,fields}) => { //校验失败 })
new Schema(descriptor ) 直接开始实例化了,我们看看 Schema 是如何定义的?
二、Schema 源码分析
Schema 的构造函数:主要分为三步:
1、this 上定义实例属性 rules 为 null。
// 构造函数 var Schema = function () { function Schema(descriptor) { // 1、实例属性 rules 默认值为空 this.rules = null; // 2、私有属性 _messages 设置初始化值 this._messages = messages; // 3、正式开始构建实例 this.define(descriptor); } return Schema; }(); Schema.warning = warning; Schema.messages = messages; Schema.validators = validators; exports['default'] = Schema;
2、this 上定义一个实例私有属性 _message ,初始化值为:
function newMessages() { ... } var messages = newMessages();
3、调用原型链 define 方法,传参 descriptor 。
descriptor 是实例化时传入的校验规则。
由上可以看到,Schema 原型链上 添加了 register、warning、messages、validators 四个方法。
2.1、warning
在实例化 Schema 之前设置 warning 方法,只要 warning 方法设置为一个空函数就能够屏蔽控制台警告。
Schema.warning = () => {} // don't print warning message when in production env or node runtime
可以发现 warning 本身就被设为了一个空函数,只有在开发环境或非 node运行时,才会用 console.warn 打印出 errors 数组中的每一个 error。
var warning = function warning() {}; // don't print warning message when in production env or node runtime if (typeof process !== 'undefined' && process.env && process.env.NODE_ENV !== 'production' && typeof window !== 'undefined' && typeof document !== 'undefined') { warning = function warning(type, errors) { if (typeof console !== 'undefined' && console.warn && typeof ASYNC_VALIDATOR_NO_WARNING === 'undefined') { if (errors.every(function (e) { return typeof e === 'string'; })) { console.warn(type, errors); } } }; }
2.2、message
Schema 中的 message 方法实质是根据不同类型校验失败后错误提示使用的提示信息模板。官方提供了一个默认的模板:
function newMessages() { return { "default": 'Validation error on field %s', required: '%s is required', "enum": '%s must be one of %s', whitespace: '%s cannot be empty', date: { format: '%s date %s is invalid for format %s', parse: '%s date could not be parsed, %s is invalid ', invalid: '%s date %s is invalid' }, types: { string: '%s is not a %s', method: '%s is not a %s (function)', array: '%s is not an %s', object: '%s is not an %s', number: '%s is not a %s', date: '%s is not a %s', "boolean": '%s is not a %s', integer: '%s is not an %s', "float": '%s is not a %s', regexp: '%s is not a valid %s', email: '%s is not a valid %s', url: '%s is not a valid %s', hex: '%s is not a valid %s' }, string: { len: '%s must be exactly %s characters', min: '%s must be at least %s characters', max: '%s cannot be longer than %s characters', range: '%s must be between %s and %s characters' }, number: { len: '%s must equal %s', min: '%s cannot be less than %s', max: '%s cannot be greater than %s', range: '%s must be between %s and %s' }, array: { len: '%s must be exactly %s in length', min: '%s cannot be less than %s in length', max: '%s cannot be greater than %s in length', range: '%s must be between %s and %s in length' }, pattern: { mismatch: '%s value %s does not match pattern %s' }, clone: function clone() { var cloned = JSON.parse(JSON.stringify(this)); cloned.clone = this.clone; return cloned; } }; } var messages = newMessages();
上述是官方提供的默认模板提示信息,还可以根据自己的项目进行定制化,因为官方也提供了 deepMerge 方法:
_proto.messages = function messages(_messages) { if (_messages) { this._messages = deepMerge(newMessages(), _messages); } return this._messages; }; /* 深度合并 */ function deepMerge(target, source) { if (source) { // 更新 message for (var s in source) { if (source.hasOwnProperty(s)) { var value = source[s]; if (typeof value === 'object' && typeof target[s] === 'object') { target[s] = _extends({}, target[s], value); } else { target[s] = value; } } } } return target; }
所以可以根据自己项目需求,可以自己定制化一个 message 校验提示。
2.3、validators
validator 主要作用是为用户提供各种数据类型的验证方法。
var validators = { string: string, method: method, number: number, "boolean": _boolean, regexp: regexp, integer: integer, "float": floatFn, array: array, object: object, "enum": enumerable, pattern: pattern, date: date, url: type, hex: type, email: type, required: required, any: any };
以对string类型的判断为例
rule: 在源descriptor中,与要校验的字段名称相对应的校验规则。始终为它分配一个field属性,其中包含要验证的字段的名称。
//这个样子 { [field: string]: RuleItem | RuleItem[] } //例子 {name:{type: "string", required: true, message: "Name is required"}}
2.4、register
除了 validators 方法,还提供了 register 方法,用于新增类型校验器:
Schema.register = function register(type, validator) { // validator 必须是函数 if (typeof validator !== 'function') { //无法按类型注册验证程序,验证程序不是函数 throw new Error('Cannot register a validator by type, validator is not a function'); } validators[type] = validator; };