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; };