深入掌握ant-design的form異步校驗(yàn)(一)

一、前言
本文基于開源項(xiàng)目:

https://github1s.com/ant-design/ant-design

https://github.com/yiminghe/async-validator

很多小伙伴對(duì)antd的form表單校驗(yàn)不是很清楚,有些時(shí)候?qū)懥艘恍┬r?yàn)規(guī)則然后不是自己想要實(shí)現(xiàn)的效果、或者不清楚校驗(yàn)規(guī)則是什么無從寫起。

下面我們一起來學(xué)習(xí)學(xué)習(xí)form的校驗(yàn)~

二、validateFields
 廣東靚仔從文檔找了個(gè)demo,代碼如下:

<Form form={form} initialValues={{ aaa: '2' }}>
  <Form.Item name="aaa">
    <Input
      onChange={async () => {
        await sleep(0);
        try {
          await form.validateFields();
        } catch (e) {
        // do nothing
      }
     }}
    />
  </Form.Item>
<Form>
            
我們來看看validateFields的返回示例:

validateFields()
  .then(values => {
    /*
  values:
    {
      username: 'username',
      password: 'password',
    }
  */
  })
  .catch(errorInfo => {
    /*
    errorInfo:
      {
        values: {
          username: 'username',
          password: 'password',
        },
        errorFields: [
          { name: ['password'], errors: ['Please input your Password!'] },
        ],
        outOfDate: false,
      }
    */
  });
            
AntDesign的表單校驗(yàn)是基于async-validator,是支持異步校驗(yàn)的。  

三、async-validator介紹
官方介紹:Validate form asynchronous.
簡單理解:async-validator是一個(gè)表單的異步驗(yàn)證的第三方庫。
安裝
npm i async-validator
使用
它基本用法包括定義描述符,將它分配給模式并將要驗(yàn)證的對(duì)象和回調(diào)函數(shù)傳遞給validate模式的方法:

import Schema from 'async-validator';
const descriptor = {
  name: {
    type: 'string',
    required: true,
    validator: (rule, value) => value === 'muji',
  },
  age: {
    type: 'number',
    asyncValidator: (rule, value) => {
      return new Promise((resolve, reject) => {
        if (value < 18) {
          // reject錯(cuò)誤信息
          reject('too young');
        } else {
          resolve();
        }
      });
    },
  },
};
const validator = new Schema(descriptor);
validator.validate({ name: 'muji' }, (errors, fields) => {
  if (errors) {
    // 驗(yàn)證失敗,errors 是一個(gè)包含所有錯(cuò)誤的數(shù)組
    // fields 是一個(gè)以字段名稱為鍵的對(duì)象
    // errors per field
    return handleErrors(errors, fields);
  }
  // 這里則是驗(yàn)證通過
});

// PROMISE USAGE
validator.validate({ name: 'muji', age: 16 }).then(() => {
  // 驗(yàn)證通過或沒有錯(cuò)誤消息
}).catch(({ errors, fields }) => {
  return handleErrors(errors, fields);
});
簡單梳理下:傳入驗(yàn)證規(guī)則對(duì)象,可以新建一個(gè)驗(yàn)證器對(duì)象。驗(yàn)證器對(duì)象的validate方法用于驗(yàn)證數(shù)據(jù)是否符合驗(yàn)證規(guī)則。

Validate有三個(gè)參數(shù):

source:要驗(yàn)證的對(duì)象(必需)。

options:描述驗(yàn)證處理選項(xiàng)的對(duì)象(可選)。

callback:驗(yàn)證完成時(shí)調(diào)用的回調(diào)函數(shù)(可選)。

可以看出Validate返回了一個(gè)Promise 對(duì)象

rules規(guī)則
function(rule, value, callback, source, options)
rule:源描述符中的驗(yàn)證規(guī)則,對(duì)應(yīng)于正在驗(yàn)證的字段名稱。它總是被分配一個(gè)field帶有被驗(yàn)證字段名稱的屬性。

value:正在驗(yàn)證的源對(duì)象屬性的值。

callback:驗(yàn)證完成后調(diào)用的回調(diào)函數(shù)。它期望傳遞一個(gè)Error實(shí)例數(shù)組來指示驗(yàn)證失敗。如果檢查是同步的,可以直接返回一個(gè)falseorError或Error Array。

source:傳遞給validate方法的源對(duì)象。

options:其他選項(xiàng)。

options.messages:包含驗(yàn)證錯(cuò)誤消息的對(duì)象,將與 defaultMessages 深度合并。

傳遞給validate或asyncValidate傳遞給驗(yàn)證函數(shù)的選項(xiàng),以便在驗(yàn)證函數(shù)中引用瞬態(tài)數(shù)據(jù)(例如模型引用)。但是,保留了一些選項(xiàng)名稱;如果使用選項(xiàng)對(duì)象的這些屬性,它們將被覆蓋。保留的屬性messages是exception和error。



我們經(jīng)常寫rules為對(duì)象數(shù)組,針對(duì)單個(gè)字段的多個(gè)驗(yàn)證規(guī)則進(jìn)很有用:

const descriptor = {
  email: [
    { type: 'string', required: true, pattern: Schema.pattern.email },
    {
      validator(rule, value, callback, source, options) {
        const errors = [];
        // 測(cè)試郵箱地址是否已經(jīng)存在于數(shù)據(jù)庫中
        // 如果確實(shí)則將驗(yàn)證錯(cuò)誤添加到錯(cuò)誤數(shù)組
        return errors;
      },
    },
  ],
};
type類型
可以使用的類型如下:

string: 必須是類型string。This is the default type.

number: 必須是類型number。

boolean: 必須是類型boolean。

method: 必須是類型function。

regexp: 必須是RegExp創(chuàng)建新的時(shí)不產(chǎn)生異常的實(shí)例或字符串RegExp。

integer: 必須是類型number和整數(shù)。

float: 必須是類型number和浮點(diǎn)數(shù)。

array: 必須是由 確定的數(shù)組Array.isArray。

object: 必須是 typeobject而不是Array.isArray。

enum: 值必須存在于enum.

date:值必須是有效的,由Date

url: 必須是類型url。

hex: 必須是類型hex。

email: 必須是類型email。

any: 可以是任何類型。

asyncValidator異步驗(yàn)證器
我們可以自定義指定字段的異步驗(yàn)證功能,代碼如下:

const fields = {
  asyncField: {
    asyncValidator(rule, value, callback) {
      ajax({
        url: 'xx',
        value: value,
      }).then(function(data) {
        callback();
      }, function(error) {
        callback(new Error(error));
      });
    },
  },

  promiseField: {
    asyncValidator(rule, value) {
      return ajax({
        url: 'xx',
        value: value,
      });
    },
  },
};
validator驗(yàn)證器
我們可以為指定字段自定義驗(yàn)證功能,代碼如下:
const fields = {
  field: {
    validator(rule, value, callback) {
      return value === 'test';
    },
    message: 'Value is not equal to "test".',
  },

  field2: {
    validator(rule, value, callback) {
      return new Error(`${value} is not equal to 'test'.`);
    },
  },
 
  arrField: {
    validator(rule, value) {
      return [
        new Error('Message 1'),
        new Error('Message 2'),
      ];
    },
  },
};

四、總結(jié)
    在我們閱讀完官方文檔后,我們一定會(huì)進(jìn)行更深層次的學(xué)習(xí),比如看下框架底層是如何運(yùn)行的,以及源碼的閱讀。
    這里廣東靚仔給下一些小建議:
在看源碼前,我們先去官方文檔復(fù)習(xí)下框架設(shè)計(jì)理念、源碼分層設(shè)計(jì)
閱讀下框架官方開發(fā)人員寫的相關(guān)文章
借助框架的調(diào)用棧來進(jìn)行源碼的閱讀,通過這個(gè)執(zhí)行流程,我們就完整的對(duì)源碼進(jìn)行了一個(gè)初步的了解
接下來再對(duì)源碼執(zhí)行過程中涉及的所有函數(shù)邏輯梳理一遍

作者:廣東靚仔


歡迎關(guān)注:前端早茶