🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>[success] # 开始实战 ~~~ 1.现在有个需求有一个接口是创建人员的,要求人员的名字不能为空,剩下 的都可以为空,随着业务可能后续还会增加越来越多和人有关的字段,例如 身高,体重,职业,这个接口也会在多个页面重复使用,但如果页面挨个添 加,容易出现遗漏,因此根据这个我们构建了一套管理数据分离 ~~~ >[info] ## 从'Model' 模块文件夹开始 ~~~ 1.model 文件夹下的'BaseModel.js' 文件是所有自定义接口类的 基类,这里基类可以帮我们将字段 和 字段验证方法进行匹配,可以帮我们 进行数据自动赋值,也可以根据我们自己的业务需求进行二次添加 2.model 文件下的'MyPerson.js' 文件是一个本章节的接口验证管理类,需要 根据业务不同,自己维护各自的模块类 ~~~ >[danger] ##### BaseModel -- 模块管理基类 ~~~ 1.说明文件中导入的'KEY_DECO_VALIDATORS' 是一个'Symbol'变量: KEY_DECO_VALIDATORS = Symbol('validators') 2.'reflect-metadata' 是一个第三方的用来强化'Reflect' 映射的一个库 ~~~ ~~~ import {KEY_DECO_VALIDATORS} from '../untils/decorators' import 'reflect-metadata' export default class BaseModel{ // 查当前类生成的实例,对应的指定字段映射的验证类 decoratorsOf( property, metaKey = KEY_DECO_VALIDATORS) { const rs = Reflect.getMetadata(metaKey, this, property) return Array.isArray(rs) ? rs : [rs] } async validatorOf(property, args) { const vArr = this.decoratorsOf(property) if (vArr) { // 获取当前验证属性值 const val = this[property] for (const it of vArr) { // 调用当前映射的验证装饰所对应的类验证方法 if (it.validate && !(await it.validate(val, args))) { return new Error(it.errorMessage) }else{ return new Error('当前验证方法不存在') } } } } } ~~~ >[danger] ##### 需要根据需要实现 -- MyPerson类 ~~~ 1.这个类应该根据你的需要和业务去实现,现在虚拟想出的业务就是有个接 口用来提交个人的信息 2.所有这系列的类都需要继承'BaseModel.js',因为'BaseModel. js' 有这些模 块共同的方法 3.需要对需要验证的字段加上对应验证的装饰器用来修饰 ~~~ ~~~ import BaseModel from './BaseModel' import required from '../baseValidator/RequiredValidator' export default class MyPerson extends BaseModel{ @required(false,'不能为空') name = '' } ~~~ >[info] ## 从'baseValidator' 开始验证 ~~~ 1.'baseValidator' 文件夹跟'model' 文件夹的思路一致的,有一个基类'BaseModel.js' 文件,这个是所有验证的基类,可以根据自己的业务做二次开发 2.'baseValidator' 文件夹也会提供一些常用的基本验证规则的类,这些类都是通过 继承'BaseModel.js' 基类实现,例如常见的'必填','正则'等 3.最后的使用其实调用就是'validatorOf'方法 ~~~ >[danger] ##### BaseValidator 验证的基类 ~~~ 1.验证的基类,用来规定后续验证,可以自定义格式,需要指定对应的报错提示 ~~~ ~~~ /** * 验证的基础模板 类似验证的接口 * @param {string} errorMessage - 验证的报错信息 */ export default class BaseValidator { constructor(errorMessage = 'Invalid Data') { this.errorMessage = errorMessage } /** * @return {boolean} 验证规则返回的需要是布尔类型 * **/ async validate(value, args) { return false } } ~~~ >[danger] ##### 常用的验证类 必填-- Required ~~~ 1.必填装饰验证的封装 ~~~ ~~~ import BaseValidator from './BaseValidator' import {validatorImpl} from'../untils/decorators' /** * 验证是否必填 * @param {string} errorMessage - 验证的报错信息 * @param {boolean} allowEmptyString - 自定义验证规则 */ class Required extends BaseValidator { constructor(allowEmptyString=false, errorMessage) { super(errorMessage) this.allowEmptyString = allowEmptyString } /** * @return {boolean} 通过正则验证必填 * **/ async validate(value, args) { return value !== null && (this.allowEmptyString || !/^\s*$/.test(value)) } } export default function required(allowEmptyString,errorMessage) { return validatorImpl( new Required(allowEmptyString,errorMessage)) } ~~~ >[info] ## untils -- 编写配合工具 ~~~ 1.做映射关系,和映射全局'key' ~~~ >[danger] ##### 装饰器开始 -- decorators.js ~~~ 1.可以发现这个方法是配合,装饰器方法使用,例子: export default function required(allowEmptyString,errorMessage) { return validatorImpl( new Required(allowEmptyString,errorMessage)) } 2.整个方法思路就是用一个数组去保存对应属性的映射验证,往往有时候 字段是需要多个验证规则,因此可能需要多个装饰器来修饰, 'Reflect.getMetadata'用来判断当前装饰器是否有对应映射关系,如果没有 就会返回'undefind',在利用'defineMetadata' 添加一个空数组作为映射 的'value',再将对应的验证类添加到这个映射数组中 ~~~ ~~~ export const KEY_DECO_VALIDATORS = Symbol('validators') export function validatorImpl (ins) { return (target, propKey) => { let vArr = Reflect.getMetadata(KEY_DECO_VALIDATORS, target, propKey) if (!vArr) { vArr = [] Reflect.defineMetadata(KEY_DECO_VALIDATORS, vArr, target, propKey) } vArr.push(ins) } } ~~~