原創文章, 轉載請私信. 訂閱號 tastejava 學習加思考, 仔細品味java之美
前端UI框架與async-validator介紹
- VantUI是一款有贊出品的基於Vue的前端手機端開發框架
- ElementUI和MintUI是兩款餓了麼公司出品的基於Vue的UI框架, ElementUI適用於電腦端, MintUI適用於手機端
- async-validator是一款基於js的異步數據校驗插件(當前github上已有117k個倉庫使用了async-validator)
async-validator有兩種版本, 當前文章環境用的是由原版衍生出來的一種版本.git地址如下:async-validator github
應用場景
公司內一個項目電腦端採用ElementUI框架, 手機端採用VantUI框架進行開發.然而當前VantUI最新版本表單組件van-field只提供了錯誤信息接口error-message, 並沒有提供表單數據的校驗工具. 因爲本身ElementUI表單校驗組件使用了async-validator, 爲了儘量保持項目整體一致, 所以在VantUI手機端項目中對async-validator簡單封裝對錶單數據進行校驗.
使用方法
async-validator部分官方文檔如下
import schema from '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
});
使用總共分四步,
- 先引入schema
- 創建descriptor字段校驗規則
- 用descriptor創建一個schema實例validator
- 調用實例validator的validate方法, 檢驗傳入的數據是否正確
封裝工具類
async-validator功能十分強大, 官方文檔簡潔清晰, 但是應用於實際項目中還需要簡單封裝.總共封裝一個validator.js工具類和一個commonRules.js用於快速創建常用規則.
在validator工具類中採用VantUI的Notify組件來進行錯誤提示具體代碼如下.
validator.js
import schema from 'async-validator';
import { Notify } from 'vant';
/**
* 根據校驗條件校驗輸入數據
* @param descriptor 校驗條件
* @param source 輸入數據
* @returns {Promise<any>} 校驗結果
*/
export default function validate (descriptor, source) {
let validator = new schema(descriptor);
let validated = new Promise((resolve, reject) => {
validator.validate(source).then(() => {
// validation passed or without error message
resolve('success');
// eslint-disable-next-line no-unused-vars
}).catch(({errors, fields}) => {
if (errors) {
Notify(errors[0].message);
reject('error');
}
});
});
return validated;
}
在commonRules通用規則中封裝一個常用的根據js假值判斷非空規則NotNull,和一個可以傳入自定義判斷邏輯的通用規則Validated, 在Validated基礎上提供Length校驗字符串長度通用規則,這三個規則應該能滿足項目校驗需要.具體代碼如下.
commonRules.js
// 通用校驗非空規則
/**
* @param {string} type 要校驗字段類型, 如 string, array, number
* @param {string} errorMsg 校驗失敗時錯誤信息內容
*/
function NotNull(type, errorMsg) {
this.type = type;
this.required = true;
this.asyncValidator = (rule, value) => {
return new Promise((resolve, reject) => {
if (!value || value == 'undefined') {
reject(errorMsg);
return;
}
if (Array.isArray(value)) {
// 不允許空數組
if (value.length == 0) {
reject(errorMsg);
return;
}
}
resolve();
});
}
}
// 使用自定義校驗規則
/**
* @param {string} type 要校驗字段類型, 如 string, array, number
* @param {function} processor 規則函數, 校驗錯誤時返回錯誤信息, 否則無返回值
* value => {
* if (value == "undefined") {
* let errMsg = "";
* return errMsg;
* }
* }
* @param {boolean} [required] 是否必填 true | false
*/
function Validated(type, processor, required) {
if (!required) {
required = false;
}
this.type = type;
this.required = required;
this.asyncValidator = (rule, value) => {
return new Promise((resolve, reject) => {
if (!required && !value) {
// 非必填並且value不存在時, 不執行校驗規則
resolve();
return;
}
let error = processor(value);
if (!error) {
resolve();
} else {
reject(error);
}
});
}
}
/**
* 校驗字符串長度規則
* @param {object} args 校驗字符串長度需要傳入的參數對象有6個屬性
* @param {boolean} [args.required] 是否必填 boolean
* @param {int} [args.min] 字符串最短長度, 不填寫將不限制最短長度
* @param {int} args.max 字符串最大長度
* @param {string} [args.errorMsg] 表單必填時,無數據時報錯信息
* @param {string} [args.minErrorMsg] 小於最小長度報錯信息
* @param {string} args.maxErrorMsg 大於最大長度報錯信息
* @param {function} [args.processor] 校驗長度後額外的校驗規則
* @returns {object} {Validated}
* @constructor
*/
function Length(args) {
return new Validated('string', value => {
// 如果必填並且沒填寫時返回錯誤信息
if (!value || value == "undefined") {
if (args.required) {
return args.errorMsg;
}
if (!args.required) {
// 非必填情況
return;
}
}
if (!args.min || args.min == "undefined") {
args.min = 0;
}
if (String(value).length < args.min) {
return args.minErrorMsg;
}
if (String(value).length > args.max) {
return args.maxErrorMsg;
}
if (args.processor) {
// 如果額外校驗存在, 執行對應的校驗方法
return args.processor(value);
}
}, args.required);
}
export {
NotNull,
Validated,
Length
};
工具類和通用規則的使用
此時在Vue組件中使用只需要引入要使用的規則和工具方法即可, 關鍵代碼如下.
// 引入校驗工具類
import validate from '@/utils/validator';
import {
NotNull,
Validated
} from '@/utils/commonRules';
// 定義校驗數據方法
validateFormData: function () {
// 定義校驗規則
let descriptor = {
xm: new NotNull('string', true, '請輸入正確的姓名'),
jcjzd: new Validated('string', true, '經常居住地需大於6位字符且不得超過100位字符',
value => {
if (value && value != 'undefined' && value.length > 6 && value.length <= 100) {
return true;
} else {
return false;
}
})
};
// 獲取校驗結果的promise對象
// descriptor爲上面構造的校驗規則, this.formData爲當前表單要校驗的數據
let validated = validate(descriptor, this.formData);
// 將promise對象返回給調用者
return validated;
}
// 調用校驗方法
addSqrAndReturn: function () {
const validated = this.validateFormData();
validated.then(() => {
// 執行校驗通過邏輯, 比如調用接口
}).catch(() => {
// 執行校驗失敗邏輯, 比如打印日誌
});
}
總結
async-validator與服務器端的validator核心思想都是將數據校驗的邏輯和規則分離, 讓開發者專注於數據校驗規則的編寫. 到此就可以在VantUI中使用async-validator驗證表單數據合法性了.
設計
不推薦直接在每個頁面中引入NotNull, Validated, Length三個通用規則, 應該單獨維護一個包含所有校驗規則的js模塊, 真正做到頁面與表單數據校驗分離其中的具體校驗規則完全可以由三個通用規則派生出來.