VantUI(ZanUI)框架使用async-validator进行表单数据校验

原创文章, 转载请私信. 订阅号 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
});

使用总共分四步,

  1. 先引入schema
  2. 创建descriptor字段校验规则
  3. 用descriptor创建一个schema实例validator
  4. 调用实例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} 校验结果
 */
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模块, 真正做到页面与表单数据校验分离其中的具体校验规则完全可以由三个通用规则派生出来.

你可能感兴趣的:(前端)