时间:2021-05-25
简单的表单验证
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.jsvar 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表单验证功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文实例讲述了javascript设计模式–装饰模式原理与应用。分享给大家供大家参考,具体如下:介绍:装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外
装饰模式是一种经典的类功能扩展模式,其精髓在装饰类使用继承加聚合的方式获得接口和要实现对象,然后通过自己实现扩展接口作用装饰模式通过装饰类动态地将责任附加到对象
1.装饰模式(Decorator)的定义:又名包装(Wrapper)模式,装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。2.装饰模式以对
本文实例讲述了java设计模式之装饰模式原理与用法。分享给大家供大家参考,具体如下:装饰模式能在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它
定义:装饰者模式就是不修改原类代码和继承的情况下动态扩展类的功能。传统的编程模式都是子类继承父类实现方法重载,使用装饰器模式,只需添加一个新的装饰器对象,更加灵