从表单校验看JavaScript策略模式的使用详解


Posted in Javascript onOctober 17, 2020

众所周知的是,表单确实在前端,唔,或者说在网页中占有不小的比重。事实上,几乎每一个中大型网站都会有“登录注册”以验证用户信息、防止一些不可名状的隐患。。。

那么表单的优劣就成了前端开发者急需解决的问题。其实我更愿意称为“代码的可读性”或“可复用性”以及“是否冗杂”。

表单也有“优劣”?你在开玩笑嘛?
我想你可以认真看下下面的代码,它用到了一些“新知识”:

<form action="xxx" id="registerForm">
	请输入用户名:<input type="text" name="userName" id="name" />
	请输入密码:<input type="text" name="password" id="pass" />
	请输入手机号:<input type="text" name="phoneNumber" id="phone" />
	<button>提交</button>
</form>

用户名、密码、手机号这应该是表单中最常见的了,好,我们就以此分析!

上面这些只是简单的演示效果,你完全可以用css的valid/invalid、HTML5的required/pattern来配合完成。

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

但即使这样,你也不会觉得它很完美 —— 现在表单只有三条,如果某一天它增加到了N条,即使是「复制粘贴」也拯救不了你!

就在这时,你想到了 策略模式 (看,JS总是会让你“灵光一现”)
说起策略模式,很自然地,要遵循 暴露接口和实现逻辑分离 的原则。

策略模式指的是定义一系列的算法,把它们一个个封装起来。将不变的部分和变化的部分隔开是每个设计模式的主题,策略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来
一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类 Context,Context 接受客户的请求,随后把请求委托给某一个策略类。要做到这点,说明 Context 中要维持对某个策略对象的引用
——《JavaScript设计模式与开发实践》

那么,第一步我们很显然要把这些校验逻辑都封装成【策略对象】:

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

接下来我们要实现一个“暴露出去的”、“作为调用的”方法类 —— 它将作为context(上下文),负责接收用户的请求并委托给验证对象stratrgies:

var Validator=function(){
	this.cache=[]; //用于保存接收到的校验规则
};
Validator.prototype.add=function(dom,rule,errorMsg){
	var ary=rule.split(':');
	this.cache.push(function(){
		var strategy=ary.shift();
		ary.unshift(dom.value);
		ary.push(errorMsg);
		return strategies[strategy].apply(dom,ary); //调用strategies对象的指定方法对象,并规定在函数对象内部this指向dom元素,ary作为参数传入
	});
};
Validator.prototype.start=function(){
	for(var i=0,validatorFunc;validatorFunc=this.cache[i++];){
		var msg=validatorFunc();
		if(msg){
			return msg;
		}
	}
}

使用:

var validataFunc=function(){
	var validator=new Validator();
	
	//添加校验规则
	validator.add(registerForm.userName,'isNoneEmpty','用户名不能为空');
	validator.add(registerForm.password,'minLength:6','密码长度不能少于6位');
	validator.add(registerForm.phoneNumber,'isMobile','手机号码格式不正确');
	
	var errMsg=validator.start(); //获得校验结果
	return errorMsg; //返回
}

var registerForm=document.getElementById('registerForm')
registerForm.onsubmit=function(){
	var errorMsg=validataFunc();
	if(errorMsg){
		//触发错误提示
		return false; //并阻止表单提交
	}
}

我们可以看到的是:当我们往 validator 对象里添加完一系列的校验规则之后,会调用 validator.start() 方法来启动校验。如果 validator.start() 返回了一个确切的 errorMsg 字符串当作返回值,说明该次校验没有通过,此时需让 registerForm.onsubmit 方法返回 false 来阻止表单的提交。

这样确实比之前好很多:至少在我们修改验证规则时显得毫不费力:

validator.add(registerForm.userName,'minLength:2','用户名不能少于2位')

但是问题也就随之而来了:我们把对于用户名的验证规则“不能为空”改为了“不能少于两位”,那么就不能验证“是否为空”了。

能不能像element-ui一样可以自定义多种验证规则 呢?就像这样:

validator.add(registerForm.userName,[{
	strategy:'isNoneEmpty',
	errorMsg:'用户名不能为空'
},{
	strategy:'minLength:2',
	errorMsg:'用户名长度不能少于2位'
}])

现在“rule”是数组-对象的形式了,我们需要把add函数改一下:

Validator.prototype.add=function(dom,rules){
	var self=this;
	for(var i=0,rule;rule=rules[i++];){
		(function(rule){
			var strategyAry=rule.strategy.split(':');
			var errorMsg=rule.errorMsg;
			self.cache.push(function(){
				var strategy=strategyAry.shift();
				strategyAry.unshift(dom.value);
				return strategies[strategy].apply(dom,strategyAry);
			});
		})(rule)
	}
}

策略模式的优点

利用组合、委托、多态等技术和思想,可以有效地避免多重条件选择语句(关于这一点,笔者在 这篇文章 中做了详细说明);完美实现了设计模式都应该具有的“对外开放-封闭”原则,基于策略模式实现的规则大多易于扩展、易于使用避免了大量CV的工作

到此这篇关于从表单校验看JavaScript策略模式的使用详解的文章就介绍到这了,更多相关JavaScript策略模式使用内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
如果文字过长,则将过长的部分变成省略号显示
Jun 26 Javascript
Raphael带文本标签可拖动的图形实现代码
Feb 20 Javascript
正负小数点后两位浮点数实现原理及代码
Sep 06 Javascript
js创建对象的区别示例介绍
Jul 24 Javascript
jQuery对象和DOM对象之间相互转换的方法介绍
Feb 28 Javascript
深入理解javascript作用域第二篇之词法作用域和动态作用域
Jul 24 Javascript
JavaScript学习笔记整理_简单实现枚举类型,扑克牌应用
Sep 19 Javascript
微信小程序开发图片拖拽实例详解
May 05 Javascript
微信JSAPI Ticket接口签名详解
Jun 28 Javascript
javascript实现文字跑马灯效果
Jun 18 Javascript
小程序实现上下切换位置
Nov 16 Javascript
EXTJS7实现点击拖拉选择文本
Dec 17 Javascript
关于IDEA中的.VUE文件报错 Export declarations are not supported by current JavaScript version
Oct 17 #Javascript
JS页面动态绘图工具SVG,Canvas,VML介简介
Oct 16 #Javascript
DWR内存兼容及无法调用问题解决方案
Oct 16 #Javascript
JS pushlet XMLAdapter适配器用法案例解析
Oct 16 #Javascript
jQuery zTree如何改变指定节点文本样式
Oct 16 #jQuery
vue使用swiper实现左右滑动切换图片
Oct 16 #Javascript
详解webpack的clean-webpack-plugin插件报错
Oct 16 #Javascript
You might like
php官方微信接口大全(微信支付、微信红包、微信摇一摇、微信小店)
2015/12/21 PHP
CI框架中$this-&gt;load-&gt;library()用法分析
2016/05/18 PHP
微信公众平台开发-微信服务器IP接口实例(含源码)
2017/03/05 PHP
PHP让数组中有相同值的组成新的数组实例
2017/12/31 PHP
php根据地址获取百度地图经纬度的实例方法
2019/09/03 PHP
hover的用法及live的用法介绍(鼠标悬停效果)
2013/03/29 Javascript
解析js如何获取当前url中的参数值并复制给input
2013/06/23 Javascript
通过复制Table生成word和excel的javascript代码
2014/01/20 Javascript
JS获取地址栏参数的几种方法小结
2014/02/28 Javascript
js中的hasOwnProperty和isPrototypeOf方法使用实例
2014/06/06 Javascript
JavaScript将取代AppleScript?
2014/09/18 Javascript
分享十五款 jQuery 社交网络分享插件
2015/05/16 Javascript
js插件dropload上拉下滑加载数据实例解析
2016/07/27 Javascript
BootStrap 图标icon符号图标glyphicons不正常显示的快速解决办法
2016/12/08 Javascript
详解Node.js实现301、302重定向服务
2017/04/07 Javascript
jQuery实现frame之间互通的方法
2017/06/26 jQuery
ReactNative列表ListView的用法
2017/08/02 Javascript
详解bootstrap导航栏.nav与.navbar区别
2017/11/23 Javascript
jquery写出PC端轮播图实例
2018/01/26 jQuery
JS实现显示当前日期的实例代码
2018/07/03 Javascript
swiper实现异形轮播效果
2019/11/28 Javascript
Python生成数字图片代码分享
2017/10/31 Python
安装完Python包然后找不到模块的解决步骤
2020/02/13 Python
通过css3动画和opacity透明度实现呼吸灯效果
2019/08/09 HTML / CSS
Myprotein丹麦官网:欧洲第一运动营养品牌
2019/04/15 全球购物
美国优质马术服装购买网站:Breeches.com
2019/12/16 全球购物
构造器Constructor是否可被override?
2013/08/06 面试题
注塑工厂厂长岗位职责
2013/12/02 职场文书
英语课前三分钟演讲稿
2014/08/19 职场文书
银行职员工作失误检讨书
2014/10/14 职场文书
初中信息技术教学反思
2016/02/16 职场文书
祝福语集锦:送给闺蜜的生日祝福语
2019/10/08 职场文书
HTML5中 rem适配方案与 viewport 适配问题详解
2021/04/27 HTML / CSS
常用的MongoDB查询语句的示例代码
2021/07/25 MongoDB
浅谈JavaScript浅拷贝和深拷贝
2021/11/07 Javascript
Android Rxjava3 使用场景详解
2022/04/07 Java/Android