用策略模式实现表单的校验

预览

GIF.gif

作为一名前端人士,在一个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

结语

策略模式的巧妙之处远远不止这些,我只是列举了其中小小的一个环节!还需要花费更多的时间去学习其中的奥秘。虽然开始学的很艰难,但是努力过后,就会陶醉在知识的海洋里!
有建议或者觉得有错误的地方可以指出来哟,让我跟随大佬们的步伐,继续努力吧!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容