阿里出品的 antd 和 ElementUI 組件庫中表單校驗默認使用的 async-validator,它在 gitbub 上也得到了 3.8k 的 star,可見這個庫十分強大,奈何只有英文文檔看的蛋疼,所以花點時間翻譯一下以便往後查看和爲新手同事提供文檔,原文都以摺疊的方式保留着,看不懂個人描述能夠展開看看原文。javascript
結合 github 上的例子能方便理解vue
(大部分緣由是我英文水平不夠,可是明明是中國人寫的爲啥不順手寫個中文的 readme 呢,雖然就算翻譯成了中文也仍是晦澀難懂。。。)java
翻譯時間: 2019/5/31ios
正文開始。git
一個用於表單異步校驗的庫,參考了 https://github.com/freeformsystems/async-validate
github
下述內容來自於 async-validate. 的早期版本
ajax
基本的使用方法:定義一個 descriptor,將它傳入 schema,獲得一個 validator。將須要校驗的對象和回調傳入 validator.validate 方法中。數據庫
注:descriptor 是對校驗規則的描述,validator 是根據校驗規則獲得的校驗器express
var schema = require('async-validator'); var descriptor = { name: { type: "string", required: true, validator: (rule, value) => value === 'muji', }, }; var validator = new schema(descriptor); validator.validate({name: "muji"}, (errors, fields) => { if(errors) { // validation failed, errors is an array of all errors // fields is an object keyed by field name with an array of // errors per field // 校驗未經過的狀況,errors 是全部錯誤的數組 // fields 是一個 object,以字段做爲 key 值,該字段對應的錯誤數組做爲 value // (其實 fields 就是把 errors 按照原對象的 key 值分組) return handleErrors(errors, fields); } // validation passed // 這裏說明校驗已經過 }); // PROMISE USAGE // Promise 式用法 validator.validate({ name: "muji", asyncValidator: (rule, value) => axios.post('/nameValidator', { name: value }), }, (errors, fields) => { if(errors) { // validation failed, errors is an array of all errors // fields is an object keyed by field name with an array of // errors per field // 校驗未經過的狀況,errors 和 fields 同上 return handleErrors(errors, fields); } // validation passed // 校驗經過 }) .then(() => { // validation passed // 校驗經過 }) .catch(({ errors, fields }) => { return handleErrors(errors, fields); })
function(source, [options], callback): Promise
source
: 須要校驗的對象(必填).options
: 校驗選項(可選).callback
: 校驗完成時的回調(必填).方法返回一個 Promise 對象:axios
then()
,說明校驗經過catch({ errors, fields })
,校驗未經過,errors, fields 含義見前面示例first
: Boolean, 碰見第一個未經過校驗的值時便調用 callback
回調,再也不繼續校驗剩餘規則。
適用狀況:校驗涉及到多個異步調用,好比數據庫查詢,而你只須要獲取首個校驗錯誤時
firstFields
: Boolean|String[], 對於指定字段,碰見第一條未經過的校驗規則時便調用 callback
回調,而再也不校驗該字段的其餘規則 ,傳入 true
表明全部字段。
Rules 也能夠是用於校驗的函數
function(rule, value, callback, source, options)
rule
: 當前校驗字段在 descriptor 中所對應的校驗規則,其中的 field 屬性是當前正在校驗字段的名稱value
: 當前校驗字段的值callback
: 在校驗完成時的回調,傳入 Error
[或者是一個數組] 表明校驗失敗,若是校驗是同步的話,直接返回 false
或 Error
或 Error
數組也能夠(注:異步校驗經過時直接不帶參數調用 callback()
,表明沒有錯誤)source
: 傳入 validate
方法的 object,也就是須要校驗的對象options
: 傳入的額外選項options.messages
: 對象包含的校驗錯誤提示信息,會被合併到默認的提示信息中傳入 validate
或 asyncValidate
的 options 被帶到了校驗函數中,以便你能夠在校驗函數中拿到數據(好比 model 引用)。然而,option中部分屬性名是被保留的,你若是使用了的話會被覆蓋掉,其中包括 messages
, exception
和 error
。
var schema = require('async-validator'); var descriptor = { name(rule, value, callback, source, options) { var errors = []; if(!/^[a-z0-9]+$/.test(value)) { errors.push( new Error( util.format("%s must be lowercase alphanumeric characters", rule.field))); } return errors; } } var validator = new schema(descriptor); validator.validate({name: "Firstname"}, (errors, fields) => { if(errors) { return handleErrors(errors, fields); } // validation passed });
在須要對一個字段設置多條校驗規則時,能夠把規則設爲一個數組,好比
var descriptor = { email: [ {type: "string", required: true, pattern: schema.pattern.email}, {validator(rule, value, callback, source, options) { var errors = []; // test if email address already exists in a database // and add a validation error to the errors array if it does return errors; }} ] }
下列是 type
可用的值:
string
: 必須是 string
. This is the default type.
number
: 必須是 number
.boolean
: 必須是 boolean
.method
: 必須是 function
.regexp
: 必須是正則或者是在調用 new RegExp
時不報錯的字符串.integer
: 整數.float
: 浮點數.array
: 必須是數組,經過 Array.isArray
判斷.object
: 是對象且不爲數組.enum
: 值必須出如今 enmu
枚舉值中.date
: 合法的日期,使用 Date
判斷url
: url.hex
: 16進制.email
: 郵箱地址.Required
required
屬性表明這個字段必須出如今對象中
Pattern
pattern
屬性表明須要符合的正則
Range
使用 min
和 max
屬性定義範圍,對於字符串和數組會與 value.length
比較,對於數字會直接與值比較
Length
使用 len
屬性直接指定長度,會與字符串和數組的 value.length
比較相等,對於數字會直接與值比較是否相等
若是 len
與 min
和 max
同時使用, len
優先。
Enumerable
可枚舉值
對於能夠枚舉出全部狀況的類型,可使用枚舉校驗,以下:
var descriptor = { role: {type: "enum", enum: ['admin', 'user', 'guest']} }
Whitespace
把僅包含空格的字段視爲錯誤是很典型的作法,爲了額外測試字段是否只有空格,添加 whitespace
屬性並設爲true。這個屬性要求字段必須爲 string
類型。
若是你想要修正用戶的輸入而不是測試有無空格,查看 transform 中去除空格的例子。
Deep Rules 深層規則
若是須要校驗一個深層的對象,你須要使用 fields
屬性來設置嵌套的規則
var descriptor = { address: { type: "object", required: true, fields: { street: {type: "string", required: true}, city: {type: "string", required: true}, zip: {type: "string", required: true, len: 8, message: "invalid zip"} } }, name: {type: "string", required: true} } var validator = new schema(descriptor); validator.validate({ address: {} }, (errors, fields) => { // errors for address.street, address.city, address.zip });
須要注意的是,若是沒有在父規則上指定 required
屬性,在校驗對象中不存在這個屬性是徹底合法的,嵌套的深層規則也不會運行。
深層規則提供了直接一個定義嵌套規則的方式,讓你能夠簡化傳遞給 schema.validate()
的 options
。
var descriptor = { address: { type: "object", required: true, options: {single: true, first: true}, fields: { street: {type: "string", required: true}, city: {type: "string", required: true}, zip: {type: "string", required: true, len: 8, message: "invalid zip"} } }, name: {type: "string", required: true} } var validator = new schema(descriptor); validator.validate({ address: {} }) .catch(({ errors, fields }) => { // now only errors for street and name });
若是你像下面這樣寫,父規則也會被校驗
var descriptor = { roles: { type: "array", required: true, len: 3, fields: { 0: {type: "string", required: true}, 1: {type: "string", required: true}, 2: {type: "string", required: true} } } }
好比用於 {roles: ["admin", "user"]}
會產生兩個錯誤,一個是數組長度不匹配,一個是缺乏了索引爲 2
的元素
defaultField
屬性能夠在 array
和 object
類型中用於校驗全部的值,它能夠是一個包含有校驗規則的對象或數組。 例子以下:
var descriptor = { urls: { type: "array", required: true, defaultField: {type: "url"} } }
注意,defaultField
是 fields
的擴展,見 deep rules.
有時候須要在校驗前修改值,強制修改成特定格式。 爲此在校驗規則中添加了 transform
, 這個屬性會在校驗前執行,以適當的方式改變原始對象的值。(也就是返回值會做用在原始對象的值上)
var schema = require('async-validator'); var sanitize = require('validator').sanitize; var descriptor = { name: { type: "string", required: true, pattern: /^[a-z]+$/, transform(value) { return sanitize(value).trim(); } } } var validator = new schema(descriptor); var source = {name: " user "}; validator.validate(source) .then(() => assert.equal(source.name, "user"));
若是沒有 transform
函數校驗會失敗由於先後空格致使正則與輸入不符,但在添加了 transform
函數後即可經過由於字段已經被清洗了(或者翻譯爲使輸入值符合預期格式)
在某些需求下,你可能須要格式化支持或者想要不一樣校驗錯誤信息。
最簡單的方式就是直接爲 message
屬性賦值:
{name:{type: "string", required: true, message: "Name is required"}}
消息能夠是任意類型的,好比 JSX
:
{name:{type: "string", required: true, message: <b>Name is required</b>}}
也能夠是函數,好比使用 vue-i18n 時:
{name:{type: "string", required: true, message: () => this.$t( 'name is required' )}}
有時候你只是須要對相同的校驗規則定義不一樣語言的提示信息,在這種狀況下爲各類語言重複定義信息就顯得不少餘。
你也能夠採起這個方案:定義你本身的提示信息並賦值給 schema
:
var schema = require('async-validator'); var cn = { required: '%s 必填', }; var descriptor = {name:{type: "string", required: true}}; var validator = new schema(descriptor); // deep merge with defaultMessages validator.messages(cn); ...
若是你要定義本身的校驗函數,最好將提示信息賦值給消息對象,並在校驗函數中經過 options.messages
訪問消息。(說實話我沒看懂是什麼意思,應該是指不要把消息硬編碼寫在校驗函數裏面而是經過option傳遞,以便修改)
你能夠對指定的字段自定義包含異步操做的校驗函數
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 }); } } };
你也可像下面這樣自定義校驗函數:
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'), ]; } }, };
var Schema = require('async-validator'); Schema.warning = function(){};