预览
作为一名前端人士,在一个web项目中,注册、登录、修改用户信息等功能的实现都离不开表单。在将用户输入的数据提交给后台之前,常常需要做一些客户端力所能及的校验工作。比如注册的时候需要校验是否填写了用户名,密码的长度是否符合规定,等等。好了,您可能会说,说出你的梦想,开始你的表演,接下来我要开始我的表演了。😜
假设现在我要写一个注册页面,在店家注册按钮之前,有如下几条校验逻辑:
用户名不能为空
密码长度不能小于6位
手机号码必须符合格式
一、表单校验的第一个版本
<html>
<body>
<form action="https://www.baidu.com" method="post" id="registerForm">
请输入用户名<input type="text" name="userName"><br>
请输入密码 <input type="password" name="password"><br>
请输入手机号码<input type="text" name="phoneNumber"><br>
<button>提交</button>
</form>
</body>
</html>
么有写CSS样式,感觉界面丑哭😭,实现功能最重要,对不?
<script>
const registerForm = document.getElementById('registerForm');
registerForm.onsubmit = function() {
if (registerForm.userName != "") {
if (registerForm.password.length >= 6) {
if (/^1[3|4|5|7|8][0-9]{9}$/.test(registerForm.phoneNumber)) {
alert('成功');
} else {
alert('请输入正确的的手机号!');
return false;
}
} else {
alert('密码不能小于六位');
return false;
}
} else {
alert("用户名不能为空!");
return false;
}
}
</script>
这是一种最常见的代码编写方式,但是他的缺点显而易见。registerForm.onsubmit函数比较庞大,包含了过多的if-else语句,如果增加一条新的校验规则,或者想把免得长度校验从6位增加到8位,要去registerForm.onsubmit内部更改,这样就违反了开放-封闭的原则。
二、用策略模式实现表单的校验
我们经常说,条条大路通罗马,在现实生活中,很多时候也有很多途径到达同一个目的地。假如我们要去某个地方旅游,我们可以这样选择:
不考虑金钱的情况下,为了节省时间,我们选择乘坐飞机
考虑钱的话,那就火车或者bus
像我这样的只能来个自行车去旅游了,这就是差距啊😭,到此为止,我们来说说主角吧,蹬蹬蹬蹬,策略模式来了。
策略模式就是定义一系列算法,把它们一个个封装起来,并且是它们可以相互替换。
用策略模式来实现表单的检验,第一步我们先来把这些校验逻辑封装成策略对象
var strategies = {
// errorMsg参数,提升了适用性
isNonEmpty: function(value, errorMsg) { //不为空
if (value === '') {
// 返回字符串true 错误信息
return errorMsg;
}
},
minLength: function(value, length, errorMsg) { //限制最小长度
if (value.length < length) {
return errorMsg;
}
},
isMobile: function(value, errorMsg) {
if (!/^1[1|5|8|7|4|3][0-9]{9}$/.test(value)) { //电话号码校验
return errorMsg;
}
}
}
接下来就是实现Validator类了。Validator负责接收用户的请求并委托给strategy对象。我们先来了解下用户是如何向Validator类发送请求的,这有助于我们知道如何去编写Validator类的代码。代码如下:
function validateFunc() {
// 校验处理 分离出去
var validator = new Validator(); //创建validator对象
// 一个个去校验
// 数组 遍历
/**********************添加校验规则**********************/
validator.add(registerForm.userName, 'isNonEmpty', '用户名不能为空');
validator.add(registerForm.password, 'minLength:6', '密码长度不能少于6位');
validator.add(registerForm.phoneNumber, 'isMobile', '手机号码格式不正确')
var errorMsg = validator.start(); //获取校验结果
// 一个个去校验
return errorMsg; //返回校验结果
}
registerForm.onsubmit = function() {
// 一票规则 数组
var errorMsg = validateFunc(); //如果errorMsg有确切的返回值,说明校验未通过,即输入的内容不符合规则
if (errorMsg) {
alert(errorMsg);
return false; //阻止表单提交
}
}
通过这段代码,我们先创建了一个validator对象,然后通过validator.add方法,往validator对象中添加一些检验规则。validator.add方法接受三个参数,
validator.add(registerForm.password, 'minLength:6', '密码长度不能少于6位');
registerForm.password为参与校验的input输入框。
'minLength:6'是一个以冒号隔开的字符串。冒号前面的minLength代表挑选的strategy对象,冒号后面的数字6表示在校验中过程中所必须的参数。'minLength:6'的意思是校验registerForm.password这个文本框输入的最小长度不能小于6。如果这个字符串中不过不包含冒号,说明教研过程中不需要额外的参数,如'isNonEmpty'&'isMobile'。
第三个参数是当被校验的值不符合规则的时,返回的错误信息。
在往validator对象里添加了一系列的校验规则后,我们就要使用validator.start()方法来启动校验。如果validator.start()返回一个确切的errorMsg字符串当作返回值,就表明校验没有通过,此时需要registerForm.onsubmit方法返回false来阻止表单的提交。
最后实现Validator类:
var Validator = function() {
this.cache = [];
}
Validator.prototype.add = function(ele, rule, errorMsg) {
var arr = rule.split(':');
this.cache.push(function() {
// 规则
var strategy = arr.shift();
arr.unshift(ele.value);
arr.push(errorMsg);
return strategies[strategy].apply(ele, arr);
});
}
Validator.prototype.start = function() {
for (var i = 0, validatorFunc; validatorFunc = this.cache[i++];) {
var msg = validatorFunc();
if (msg) {
return msg;
}
}
};
使用策略模式重构代码后,仅仅可以通过“配置”的方式就可以完成一个表单的校验,这些校验规则也可以复用在程序的任何地方,这就是我们所所得,处处适用。
在修改某个校验规则的时候,只需要编写或者改写少量的代码。假如想将用户名输入框的校验规则修改成用户名不能少于四个字符。代码如下所示:
validator.add(registerForm.userName, 'isNonEmpty', '用户名不能为空');
//改成
validator.add(registerForm.userName, 'minLength:8', '用户名长度不能小于8位');
学习中遇到的问题
(1)什么鬼?在校验失败的情况下,还会实现页面的跳转,真的让人有点受不了,所以我要说的是,一定要在registerForm.onsubmit方法返回false来阻止表单的提交。
(2)再来解释下手机号码的校验规则
isMobile: function(value, errorMsg) {
if (!/^1[1|3|4|5|7|8][0-9]{9}$/.test(value)) { //电话号码校验
return errorMsg;
}
}
表示第一位只匹配数字1,第二位匹配(3|4|5|7|8)里面的任意一个数值,剩下的9位是没有限制的,也就是可以匹配0-9之间的任意数字,最后以$结尾。test函数返回的是一个boolean值。正则表达式中 test、exec、match 方法区别http://www.cnblogs.com/meixianfeng/articles/2762273.html。
代码地址:https://github.com/SiHao24/js_pattern
结语
策略模式的巧妙之处远远不止这些,我只是列举了其中小小的一个环节!还需要花费更多的时间去学习其中的奥秘。虽然开始学的很艰难,但是努力过后,就会陶醉在知识的海洋里!
有建议或者觉得有错误的地方可以指出来哟,让我跟随大佬们的步伐,继续努力吧!