JavaScript ES6 | 使用展开运算符完成全平台校验重名逻辑封装

背景

在应用系统中创建业务对象时,需要填写表单,对于对象的名称、标识等,全平台往往有统一的功能规范。
例如:

  • 名称:统一为中文、不超过50字符、不能为空、不能与现有平台重复
  • 标识:统一为英文,不超过50字符、不能为空、不能与现有平台重复
    交互逻辑一致(填写名称/标识后,调用后台接口进行判断,后台查询数据库后,返回是否存在重名数据(true/false),存在重复则报表单校验错误,不允许表单提交),前端使用的组件也一致(使用element-UIForm组件),公共逻辑清晰,于是我尝试进行统一的规则校验逻辑方法封装,简化了大量重复代码,在使用时用展开运算符spread(...)进行引入,保证了代码的优雅和简洁。

展开(spread)运算符

展开运算符是JavaScript ES6的特性,可以用于数组、字符串、对象的解构赋值。
具体使用逻辑请参考:扩展运算符

校验逻辑方法定义

校验函数封装

定义方法入参:
1、资源英文名称
用于拼接调用后端RESTful接口,例如:校验应用重复,后端定义接口URI为:
/api/applications/nameOrKeyExisted,此时资源英文名称为applications
2、资源中文名
用于页面提示回显,例如:表单中应用名称没有填写,提示:“请填写应用名称”,应用名称已存在,提示:“应用名称重复”,此时资源中文名为“应用”
3、附加参数

  • 有些资源限定为某类型下不能重复,或某个领域内不能重复,在调用判重接口时需要传递给后端。
  • prop参数,用于表单绑定的prop定义,如果不传,默认为name和key,允许传入自定义值。
    方法前端源码(定义在通用的util.js中,在Vue工程中可以在main.js引入到全局中。)

定义方法返回:
返回对象,对象中,键对应表单 prop属性,值是一个数组,包括多种规则(特殊字符校验、非空校验、重名校验等)
utils.js:

/**
 * @entity 校验实体资源
 * @entityName 校验实体中文名
 * @options  调用校验接口,额外参数传递
 */
function getRules(entity, entityName,options) {
  let name = options?.nameProp || 'name'
  let key = options?.keyProp || 'key'
  let rules = {};
  rules[name] = validateRules(
    'name',
    entity,
    entityName,
    options?.params
  );
  rules[key] = validateRules(
    'key',
    entity,
    entityName,
    options?.params
  );
  return rules;

}
function validateRules(field, entity, entityName,extraParams) {
  let rules = [];

  let requiredRule = {
    required: true,
    message: `请输入${entityName}${field === 'key' ? '标识' : '名称'}`,
    trigger: "blur",
  };
  if (field == 'key') {
    let maxLengthRule = { max: 40, message: "不得超过40个字符", trigger: "blur" };
    rules.push(maxLengthRule);
    rules.push({ validator: keyValidator, trigger: ['blur', 'change'] })
  } else {
    let maxLengthRule = { max: 16, message: "不得超过16个字符", trigger: "blur" };
    rules.push(maxLengthRule);
    rules.push({ validator: nameValidator, trigger: ['blur', 'change'] })
  }

  rules.push(requiredRule);
  rules.push(
    {
      validator:
        nameOrKeyExistedValidator,
      entity: entity,
      extraParams: extraParams,
      entityName: entityName,
      trigger: "blur",
    }
  );
  return rules;
}
const keyValidator = (rule, value, callback) => {
  const reg = /^[a-zA-Z0-9_]+$/
  if (!reg.test(value)) {
    callback(new Error('仅支持英文、数字和下划线'))
  } else {
    callback();
  }
}
const nameValidator = (rule, value, callback) => {
  const reg = /^[a-zA-Z0-9_\u4e00-\u9fa5]+$/

  if (!reg.test(value)) {
    callback(new Error('仅支持中文、英文、数字和下划线'))
  } else {
    callback();
  }
}
const nameOrKeyExistedValidator = (rule, value, callback) => {
  if (rule.oldVal && rule.oldVal === value) {
    callback();
  } else {
    nameOrKeyExisted(rule.entity, rule.field, value,rule.extraParams).then(res => {
      if (res) {
        if (rule.field === "name") {
          callback(`${rule.entityName}名称重复`)
        } else {
          callback(`${rule.entityName}标识重复`)
        }
      } else {
        callback();
      }
    })
  }
}
  • 编辑实体时的判断逻辑(传入oldVal,避免错误的报错)
    这里的逻辑暂时没想到比较好的解决方法,所以写的比较恶心,因为原先的值可能是异步拿到的,所以需要手动赋值。传入oldVal后,当表单输入值与原先的值一致时,就不会调用后端判重接口了。
  created() {
    if (this.isEdit) {
      this.rules.name[3].oldVal = this.ruleForm.name
      this.rules.key[3].oldVal = this.ruleForm.key
    }
  }

封装后端axios请求:

export function nameOrKeyExisted(entityName, type, data, params) {
  let queryParams ={};
  if (params) {
     queryParams = {
      ...params,
      type: type,
      nameOrKey: data
     }
  } else {
     queryParams = {
      type: type,
      nameOrKey: data
    }
  }
  return $get(`/api/${entityName}/nameOrKeyExisted`, queryParams)
}

请求的封装需要后端的配合~(因为这个平台后端也是由我一手包办的,所以当然不在话下啦)

  • 后端定义接口时,只需要注意后端URI和返回值一致就可以了。

使用

 <el-form :model="esseForm" :rules="esseFormRules" ref="baseInfoForm">
...
</el-form>
 esseFormRules: {
        type: [
          {
            required: true,
            message: '请选择实体类型',
            trigger: 'blur'
          }
        ],

        ...this.$utils.validate.getRules('sem-esses', '实体',{params: {user: a}})
      },

如上,使用展开运算符,将返回的结果赋值到rules对象中,名称和标识的规则由通用的校验函数根据入参生成,该方法已经挂载到全局的$utils上,无需额外的引入成本,一次性生成了对于名称、标识的所有校验。

小结

本方法适用于校验逻辑雷同、并且需要实体创建和校验的平台,如果功规调整,也能快速适应(例如长度从限制50字符改为限制100字符),节约时间。
缺陷:校验规则函数的灵活度往往与复杂度成正比,如果需要更多特殊的校验,需要考虑是否有必要修改校验函数,可能不太适用这种方法,如果创建表单的校验逻辑差异较大,就还是建议为每个表单定义自己的rules规则。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容