js前端设计模式优化50%表单校验代码示例


Posted in Javascript onJune 21, 2022

表单校验

背景

假设我们正在编写一个注册页面,在点击注册按钮之时,有如下几条校验逻辑:

  • 用户名不能为空
  • 密码长度不能少于6位
  • 手机号码必须符合格式

常规写法:

const form = document.getElementById('registerForm');
form.onsubmit = function () {
  if (form.userName.value === '') {
    alert('用户名不能为空');
    return false;
  }
  if (form.password.value.length < 6) {
    alert('密码长度不能少于6位');
    return false;
  }
  if (!/^1[3|5|8][0-9]{9}$/.test(form.phoneNumber.value)) {
    alert('手机号码格式不正确');
    return false;
  }
  ...
}

这是一种很常见的代码编写方式,但它有许多缺点:

  • onsubmit 函数比较庞大,包含了很多 if-else 语句,这些语句需要覆盖所有的校验规则。
  • onsubmit 函数缺乏弹性,如果增加了一种新的校验规则,或者想把密码的长度从6改成8,我们都必须深入 obsubmit 函数的内部实现,这是违反开放-封闭原则的。
  • 算法的复用性差,如果在项目中增加了另外一个表单,这个表单也需要进行一些类似的校验,我们很可能将这些校验逻辑复制得漫天遍野。

如何避免上述缺陷,更优雅地实现表单校验呢?

策略模式介绍

? 策略模式是一种行为设计模式, 它能让你定义一系列算法, 把它们一个个封装起来, 并使它们可以相互替换。

真实世界类比

js前端设计模式优化50%表单校验代码示例

此图源自 refactoringguru.cn/design-patt…

假如你需要前往机场。 你可以选择骑自行车、乘坐大巴或搭出租车。这三种出行策略就是广义上的“算法”,它们都能让你从家里出发到机场。你无需深入它们的内部实现细节,如怎么开大巴、公路系统如何确保你家到机场有通路等。你只需要了解这些策略的各自特点:所需要花费的时间与金钱,你就可以根据预算和时间等因素来选择其中一种策略。

更广义的“算法”

在实际开发中,我们通常会把算法的含义扩散开来,使策略模式也可以用来封装一系列的“业务规则”。只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以用策略模式来封装它们。

策略模式的组成

一个策略模式至少由两部分组成。

第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。

第二个部分是环境类 Context,Context 接受客户的请求,随后把请求委托给某一个策略类。

利用策略模式改写

定义规则(策略),封装表单校验逻辑:

const strategies = {
  isNonEmpty: function (value, errMsg) {
    if (value === '') {
      return errMsg;
    }
  },
  minLenth: function (value, length, errMsg) {
    if (value.length < length) {
      return errMsg;
    }
  },
  isMobile: function (value, errMsg) {
    if (!/^1[3|5|8][0-9]{9}$/.test(value)) {
      return errMsg;
    }
  }
}

定义环境类 Context,进行表单校验,调用策略:

form.onsubmit = function () {
	const validator = new Validator();
	validator.add(form.userName, 'isNonEmpty', '用户名不能为空');
	validator.add(form.password, 'minLength:6', '密码长度不能少于6位');
	validator.add(form.phoneNumber, 'isMobile', '手机号码格式不正确');
	const errMsg = validator.start();
	if (errMsg) {
		alert(errMsg);
		return false;
	}
}

Validator 类代码如下:

class Validator {
	constructor() {
		this.cache = [];
	}
	add(dom, rule, errMsg) {
		const arr = rule.split(':');
		this.cache.push(() => {
			const strategy = arr.shift();
			arr.unshift(dom.value);
			arr.push(errMsg);
			return strategies[strategy].apply(dom, arr);
		})
	}
	start() {
		for (let i = 0; i < this.cache.length; i++) {
			const msg = this.cache[i]();
			if (msg) return msg;
		}
	}
}

使用策略模式重构代码之后,我们消除了原程序中大片的条件分支语句。我们仅仅通过“配置”的方式就可以完成一个表单校验,这些校验规则也能在程序中任何地方复用,还能作为插件的形式,方便地移植到其他项目中。

策略模式优缺点

优点:

  • 可以有效地避免多重条件选择语句。
  • 开放-封闭原则完美支持,将算法封装在独立的 strategy 中,使得它们易于切换,易于理解,易于扩展。
  • 可以使算法复用在系统的其他地方,避免许多重复的复制粘贴工作。

缺点:

  • 使用策略模式会在程序中增加许多策略类或策略对象
  • 要使用策略模式,必须了解所有的 strategy,了解它们的不同点,我们才能选择一个合适的 strategy。这是违反最少知识原则的。

策略模式适合应用场景

? 当你想使用对象中各种不同的算法变体, 并希望能在运行时切换算法时, 可使用策略模式。

策略模式让你能够将对象关联至可以不同方式执行特定子任务的不同子对象, 从而以间接方式在运行时更改对象行为。

? 当你有许多仅在执行某些行为时略有不同的相似类时, 可使用策略模式。

策略模式让你能将不同行为抽取到一个独立类层次结构中, 并将原始类组合成同一个, 从而减少重复代码。

? 如果算法在上下文的逻辑中不是特别重要, 使用该模式能将类的业务逻辑与其算法实现细节隔离开来。

策略模式让你能将各种算法的代码、 内部数据和依赖关系与其他代码隔离开来。 不同客户端可通过一个简单接口执行算法, 并能在运行时进行切换。

? 当类中使用了复杂条件运算符以在同一算法的不同变体中切换时, 可使用该模式。

策略模式将所有继承自同样接口的算法抽取到独立类中, 因此不再需要条件语句。 原始对象并不实现所有算法的变体, 而是将执行工作委派给其中的一个独立算法对象。

总结

在上述例子中,使用策略模式虽然使得程序中多了许多策略对象和执行策略的代码。但这些代码可以在应用中任意位置的表单复用,使得整个程序代码量大幅减少,且易维护。下次面对多表单校验的需求时,别再傻傻写一堆 if-else 逻辑啦,快试试策略模式!

更多关于js前端设计模式优化表单校验的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
javascript动画效果类封装代码
Aug 28 Javascript
jQuery live( type, fn ) 委派事件实现
Oct 11 Javascript
细说浏览器特性检测(2)-通用事件检测
Nov 05 Javascript
如何使用Jquery获取Form表单中被选中的radio值
Aug 09 Javascript
jquery弹出框的用法示例(2)
Aug 26 Javascript
js和css写一个可以自动隐藏的悬浮框
Mar 05 Javascript
JS实现在线统计一个页面内鼠标点击次数的方法
Feb 28 Javascript
通过js修改input、select默认字体颜色
Apr 19 Javascript
JavaScript数据结构与算法之队列原理与用法实例详解
Nov 22 Javascript
基于vue-cli配置lib-flexible + rem实现移动端自适应
Dec 26 Javascript
详解vue组件开发脚手架
Jun 15 Javascript
在antd中setFieldsValue和defaultVal的用法
Oct 29 Javascript
微前端qiankun改造日渐庞大的项目教程
Jun 21 #Javascript
JavaScript架构localStorage特殊场景下二次封装操作
Jun 21 #Javascript
js前端图片加载异常兜底方案
Jun 21 #Javascript
JavaScript中10个Reduce常用场景技巧
Jun 21 #Javascript
js前端面试常见浏览器缓存强缓存及协商缓存实例
Jun 21 #Javascript
JavaScript前端面试组合函数
Jun 21 #Javascript
Vue2项目中对百度地图的封装使用详解
You might like
php设计模式 Prototype (原型模式)代码
2011/06/26 PHP
PHP基于递归实现的约瑟夫环算法示例
2017/08/27 PHP
PHP实现微信提现(企业付款到零钱)
2019/08/01 PHP
Javascript操纵Cookie实现购物车程序
2006/11/23 Javascript
在Node.js中实现文件复制的方法和实例
2014/06/05 Javascript
JavaScript中匿名、命名函数的性能测试
2014/09/04 Javascript
javascript实现uploadify上传格式以及个数限制
2015/11/23 Javascript
jQuery实现获取绑定自定义事件元素的方法
2015/12/02 Javascript
老生常谈onBlur事件与onfocus事件(js)
2016/07/09 Javascript
jQuery 获取select选中值及清除选中状态
2016/12/13 Javascript
jquery实现百叶窗效果
2017/01/12 Javascript
jQuery实现frame之间互通的方法
2017/06/26 jQuery
get  post jsonp三种数据交互形式实例详解
2017/08/25 Javascript
使用jquery模拟a标签的click事件无法实现跳转的解决
2018/12/04 jQuery
Node.js中package.json中库的版本号(~和^)
2019/04/02 Javascript
js实现移动端tab切换时下划线滑动效果
2019/09/08 Javascript
Vue使用NProgress的操作过程解析
2019/10/10 Javascript
python实现的udp协议Server和Client代码实例
2014/06/04 Python
在Python中使用异步Socket编程性能测试
2014/06/25 Python
Python运算符重载用法实例
2015/05/28 Python
Python生成短uuid的方法实例详解
2018/05/29 Python
Python动态导入模块的方法实例分析
2018/06/28 Python
Flask模拟实现CSRF攻击的方法
2018/07/24 Python
详解Python3中的迭代器和生成器及其区别
2018/10/09 Python
10分钟教你用Python实现微信自动回复功能
2018/11/28 Python
基于Python3.7.1无法导入Numpy的解决方式
2020/03/09 Python
Python如何在windows环境安装pip及rarfile
2020/06/15 Python
python中return如何写
2020/06/18 Python
澳大利亚电子产品购物网站:Dick Smith
2017/02/02 全球购物
英国大码女性时装零售商:Evans
2018/08/29 全球购物
运动会广播稿200米
2014/01/27 职场文书
感恩老师的演讲稿
2014/05/06 职场文书
颐和园导游词400字
2015/01/30 职场文书
北京大学中文系教授推荐的10本小说
2019/08/08 职场文书
利用Python判断整数是否是回文数的3种方法总结
2021/07/07 Python
关于nginx 实现jira反向代理的问题
2021/09/25 Servers