全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

利用策略模式与装饰模式扩展JavaScript表单验证功能

简单的表单验证

html结构

<!-- validata.html -->
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Validata</title>
</head>
<body>
 <form id="form">
 <label for="username">账号:</label><input id="username" type="text"><br>
 <label for="password">密码:</label><input id="password" type="password"><br>
 <label for="phonenum">手机:</label><input id="phonenum" type="text"><br>
 <input id="submit" type="button" value="提交">
 </form>
 <p id="warn"></p>
 <script src="validata.js"></script>
</body>
</html>

首先先简单地实现以下这个功能

之后再用设计模式丰满

// validata.js
var form = document.getElementById('form'),
 warn = document.getElementById('warn');
var validata = function(){
 if(form.username.value === ''){
 return warn.textContent = '账号不能为空';
 }
 if(form.password.value === ''){
 return warn.textContent = '密码不能为空';
 }
 if(form.phonenum.value === ''){
 return warn.textContent = '手机号不能为空';
 }
 var msg = {
 username: form.username.value,
 password: form.password.value,
 phonenum: form.phonenum.value
 }
 //ajax('...', msg); ajax提交数据略
 return warn.textContent = '用户信息已成功提交至服务器';
}
form.submit.onclick = function(){
 validata();
}

然后分析以下代码

validata这个函数毫无复用性可言,除此之外存在两个问题

  • 函数同时承担了验证和提交两个职责,违背单一职责原则
  • 验证功能扩展性差,要想添加验证规则就必须深入函数内部,违反开放-封闭原则

所以我们需要对此进行改进

装饰模式重构

先来用装饰模式解决一下函数多职责问题

方法也很简单

改进一下AOP前置装饰函数(Function.prototype.before)

当扩展函数(beforeFn)返回false则不执行当前函数

然后令表单验证函数成为表单提交函数的前置装饰

这样提交前就会进行验证,若验证失败,就不会提交数据

var form = document.getElementById('form'),
 warn = document.getElementById('warn');
Function.prototype.before = function(beforeFn){
 var self = this;
 return function(){
 if(beforeFn.apply(this, arguments) === false)
  return;
 return self.apply(this, arguments);
 }
}//改进的AOP前置装饰函数
var validata = function(){
 if(form.username.value === ''){
 warn.textContent = '账号不能为空';
 return false;
 }
 if(form.password.value === ''){
 warn.textContent = '密码不能为空';
 return false;
 }
 if(form.phonenum.value === ''){
 warn.textContent = '手机号不能为空';
 return false;
 }
}
var submitMsg = function(){ //将提交的功能从validata函数中提取出来
 var msg = {
 username: form.username.value,
 password: form.password.value,
 phonenum: form.phonenum.value
 }
 //ajax('...', msg);
 return warn.textContent = '用户信息已成功提交至服务器';
}
submitMsg = submitMsg.before(validata);
//让表单验证函数成为表单提交函数的装饰者
form.submit.onclick = function(){
 submitMsg();
};

策略模式重构

下面就该解决函数缺乏弹性的问题

使用策略模式就需要有策略对象/类和环境对象/类

毫无疑问策略对象中就应该装着校验规则

又考虑到页面可能不止有一个验证表单

最好写成工厂-类的形式

完整代码如下

var form = document.getElementById('form'),
 warn = document.getElementById('warn');
Function.prototype.before = function(beforeFn){
 var self = this;
 return function(){
 if(beforeFn.apply(this, arguments) === false)
  return;
 return self.apply(this, arguments);
 }
}
var vldStrategy = { //策略对象-验证规则
 isNonEmpty: function(value, warnMsg){ //输入不为空
 if(value === '')
  return warnMsg;
 },
 isLongEnough: function(value, length, warnMsg){ //输入足够长
 if(value.length < length)
  return warnMsg;
 },
 isShortEnough: function(value, length, warnMsg){ //输入足够短
 if(value.length > length)
  return warnMsg;
 },
 isMobile: function(value, warnMsg){ //手机号验证
 var reg = /^1[3|5|8][0-9]{9}$/;
 if(!reg.test(value))
  return warnMsg;
 }
}
var Validator = function(){ //环境类
 this.rules = []; //数组用于存放负责验证的函数
};
Validator.prototype.add = function(domNode, ruleArr){ //添加验证规则
 var self = this;
 for(var i = 0, rule; rule = ruleArr[i++];){
 (function(rule){
  var strategyArr = rule.strategy.split(':'),
   warnMsg = rule.warnMsg;
  self.rules.push(function(){
  var tempArr = strategyArr.concat();
  var ruleName = tempArr.shift();
  tempArr.unshift(domNode.value);
  tempArr.push(warnMsg);
  return vldStrategy[ruleName].apply(domNode, tempArr);
  });
 })(rule);
 }
 return this;
};
Validator.prototype.start = function(){ //开始验证表单
 for(var i = 0, vldFn; vldFn = this.rules[i++];){
 var warnMsg = vldFn();
 if(warnMsg){
  warn.textContent = warnMsg;
  return false;
 }
 }
}
var vld = new Validator();
vld.add(form.username, [
 {
 strategy: 'isNonEmpty',
 warnMsg: '账号不能为空'
 },
 {
 strategy: 'isLongEnough:4',
 warnMsg: '账号不能小于4位'
 },
 {
 strategy: 'isShortEnough:20',
 warnMsg: '账号不能大于20位'
 }
]).add(form.password, [
 {
 strategy: 'isNonEmpty',
 warnMsg: '密码不能为空'
 }
]).add(form.phonenum, [
 {
 strategy: 'isNonEmpty',
 warnMsg: '手机号不能为空'
 },
 {
 strategy: 'isMobile',
 warnMsg: '手机号格式不正确'
 }
]);
var submitMsg = function(){
 var msg = {
 username: form.username.value,
 password: form.password.value,
 phonenum: form.phonenum.value
 }
 //ajax('...', msg);
 return warn.textContent = '用户信息已成功提交至服务器';
}
submitMsg = submitMsg.before(vld.start.bind(vld));
form.submit.onclick = function(){
 submitMsg();
};
//这里只是模拟提交,实际应该用form.onsubmit

问题分析

总结一下易错的地方还有我敲得时候遇到的问题

Validator.prototype.add = function(domNode, ruleArr){
 var self = this;
 for(var i = 0, rule; rule = ruleArr[i++];){
 (function(rule){
  var strategyArr = rule.strategy.split(':'),
   warnMsg = rule.warnMsg;
  self.rules.push(function(){
  var tempArr = strategyArr.concat();
  var ruleName = tempArr.shift();
  tempArr.unshift(domNode.value);
  tempArr.push(warnMsg);
  return vldStrategy[ruleName].apply(domNode, tempArr);
  });
 })(rule);
 }
 return this;
};

在Validator原型链上的add函数需要注意几个问题

首先添加IIFE立即执行函数解决闭包问题就不用多说了

函数内又嵌套了函数,导致了this被劫持,所以必须缓存this

var self = this;

最开始我没有拷贝这个数组而是直接使用的strategyArr

Validator.prototype.add = function(domNode, ruleArr){ //添加验证规则
 var self = this;
 for(var i = 0, rule; rule = ruleArr[i++];){
 (function(rule){
  var strategyArr = rule.strategy.split(':'),
   warnMsg = rule.warnMsg;
  self.rules.push(function(){
  // var tempArr = strategyArr.concat();
  var ruleName = strategyArr.shift();
  strategyArr.unshift(domNode.value);
  strategyArr.push(warnMsg);
  return vldStrategy[ruleName].apply(domNode, strategyArr);
  });
 })(rule);
 }
 return this;
};

第一次提交没有问题,但再次提交就会报错

这是因为第一次提交后,闭包中的strategyArr已经改变

之后的提交,对这个数组进行操作就不是预期的结果了

在这个地方我犯了一个小错误,导致我断点调试了好长时间 __冏rz

Validator.prototype.start = function(){ //开始验证表单
 for(var i = 0, vldFn; vldFn = this.rules[i++];){
 var warnMsg = vldFn();
 if(warnMsg){
  warn.textContent = warnMsg;
  return false;
 }
 }
}

改正前的错误代码是这样的

Validator.prototype.start = function(){ //开始验证表单
 for(var i = 0, vldFn; vldFn = this.rules[i++];){
 var warnMsg = vldFn();
 if(warnMsg)
  warn.textContent = warnMsg;
  return false;
 }
}

没错,只是因为少加了那层大括号

可能是之前只有一行,后来添加return false的时候忘添加了

这里我只是为了简洁才不写大括号的

我们平时千万不要这么写代码,简直挖坑给自己跳

submitMsg = submitMsg.before(vld.start.bind(vld));

添加装饰者这个地方也要注意

如果不写bind就会发生this劫持,同样会报错

以上所述是小编给大家介绍的利用策略模式与装饰模式扩展JavaScript表单验证功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


# javascript表单验证  # 从表单校验看JavaScript策略模式的使用详解  # JavaScript设计模式之策略模式实现原理详解  # javascript设计模式 – 策略模式原理与用法实例分析  # JavaScript同源策略和跨域访问实例详解  # JavaScript设计模式之策略模式详解  # javascript设计模式之策略模式学习笔记  # 轻松掌握JavaScript策略模式  # 学习JavaScript设计模式之策略模式  # javascript设计模式--策略模式之输入验证  # 学习JavaScript设计模式(策略模式)  # 详解JavaScript的策略模式编程  # 深入理解JavaScript系列(19):求值策略(Evaluation strategy)详解  # 深入理解JavaScript系列(33):设计模式之策略模式详解  # JavaScript设计模式之策略模式实例  # 怎样用Javascript实现策略模式  # 表单  # 为空  # 就会  # 报错  # 小编  # 不写  # 重构  # 在这个  # 在此  # 也要  # 是这样  # 我只  # 也很  # 给自己  # 要想  # 给大家  # 考虑到  # 千万不要  # 有我  # 再用 


相关文章: 微信小程序 五星评分(包括半颗星评分)实例代码  如何通过二级域名建站提升品牌影响力?  宝盒自助建站智能生成技巧:SEO优化与关键词设置指南  济南网站制作的价格,历城一职专官方网站?  建站VPS配置与SEO优化指南:关键词排名提升策略  如何快速搭建响应式可视化网站?  Thinkphp 中 distinct 的用法解析  如何选择可靠的免备案建站服务器?  建站主机选购指南:核心配置与性价比推荐解析  如何挑选优质建站一级代理提升网站排名?  linux top下的 minerd 木马清除方法  广东专业制作网站有哪些,广东省能源集团有限公司官网?  如何在Windows 2008云服务器安全搭建网站?  免费公司网站制作软件,如何申请免费主页空间做自己的网站?  相册网站制作软件,图片上的网址怎么复制?  如何用景安虚拟主机手机版绑定域名建站?  c# await 一个已经完成的Task会发生什么  建站DNS解析失败?如何正确配置域名服务器?  大学网站设计制作软件有哪些,如何将网站制作成自己app?  建站之星如何实现五合一智能建站与营销推广?  如何用西部建站助手快速创建专业网站?  网站制作网站,深圳做网站哪家比较好?  七夕网站制作视频,七夕大促活动怎么报名?  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  智能起名网站制作软件有哪些,制作logo的软件?  如何选择高效便捷的WAP商城建站系统?  广平建站公司哪家专业可靠?如何选择?  如何通过主机屋免费建站教程十分钟搭建网站?  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  如何通过cPanel快速搭建网站?  北京网页设计制作网站有哪些,继续教育自动播放怎么设置?  成都网站制作价格表,现在成都广电的单独网络宽带有多少的,资费是什么情况呢?  定制建站如何定义?其核心优势是什么?  如何通过FTP服务器快速搭建网站?  如何在阿里云虚拟主机上快速搭建个人网站?  网站微信制作软件,如何制作微信链接?  已有域名建站全流程解析:网站搭建步骤与建站工具选择  建站之星会员如何解锁更多建站功能?  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  济南企业网站制作公司,济南社保单位网上缴费步骤?  广州网站建站公司选择指南:建站流程与SEO优化关键词解析  网站代码制作软件有哪些,如何生成自己网站的代码?  建站之星代理如何优化在线客服效率?  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  网站网页制作专业公司,怎样制作自己的网页?  如何高效生成建站之星成品网站源码?  如何快速搭建高效服务器建站系统?  C#如何在一个XML文件中查找并替换文本内容  香港服务器选型指南:免备案配置与高效建站方案解析  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。