1. 程式人生 > 其它 >async-validator 原始碼學習筆記(五):Schema

async-validator 原始碼學習筆記(五):Schema

系列文章:

1、async-validator 原始碼學習(一):文件翻譯

2、async-validator 原始碼學習筆記(二):目錄結構

3、async-validator 原始碼學習筆記(三):rule

4、async-validator 原始碼學習筆記(四):validator

Schema 是 async-validator 庫的標準使用方式,使用 class 類的形式和建構函式方式進行定義的。

一、Schema 類使用方式

在官方文件中 Schema 的使用方式有如下幾步:

  1. 從 async-validator 中引入 Schema 類。
  2. 定義校驗規則 descriptor 。
  3. 使用 new 建立一個 Schema 的例項。
  4. 呼叫例項的 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;
};