• 从丑陋到优雅,让代码越变越美(客户端检测方法思考)


    大家都知道,客户端检测不单可以让用户获得更好的体验,而且可以通过校验数据大大减少客户端和服务器端的往返次数,减少服务器负担。在这里,小弟打算回顾一下自己在客户端检测方面的学习历程和采用方法,如果大家有什么更好的方法或者建议,欢迎提出来共享!共同进步!

    为了方便举例和说明,先构建一个简单的html页面,如下:

    html
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>JS Verify</title>
    </head>
    <body>
        
    <div>
            
    <span>请输入用户名,年龄和自我介绍:</span>
            
    <br />
            
    <span>用户名:<input type="text" id="txtName" size="20" /></span>
            
    <br />
            
    <span>年龄:<input type="text" id="txtAge" size="5" /></span>
            
    <br />
            
    <span>自我介绍:</span>
            
    <br />
            
    <span><textarea id="txtIntro" rows="10" cols="50"></textarea></span>
            
    <br />
            
    <span><input type="button" value="提交信息" /></span>
        
    </div>
    </body>
    </html>

    第一阶段是:续项强写

    每个人都基本会经过这个阶段,就是对检测内容每个都手工校验。很惭愧,自己也写过不少这样的代码。。这个阶段的代码如下:

    Code1
    function SubmitInfo()
    {
        
    var name = document.getElementById("txtName");
        
    var age = document.getElementById("txtAge");
        
    var intro = document.getElementById("txtIntro");
        
    if(name == null || name.value == "")
        {
            alert(
    "请输入用户名!");
            
    return false;
        }
        
    if(!/^[\u4E00-\u9FA5a-z0-9_]*$/gi.test(name.value))
        {
            alert(
    "用户名只能由中文,英文,数字及下划线组成!");
            
    return false;
        }
        
    if(age == null || age.value == "")
        {
            alert(
    "请输入年龄!");
            
    return false;
        }
        
    if(!/^[1-9]\d$/.test(age.value))
        {
            alert(
    "年龄必须为正整数!");
            
    return false;
        }
        
    if(intro == null || intro.value == "")
        {
            alert(
    "请输入自我介绍!");
            
    return false;
        }
        alert(
    "提交成功!");
        
    return true;
    }

    不评价这个了。。因为每个人都可能因为写这些方法检测逻辑写得眼冒星星手抽筋的!弄的经常下班了还在扑哧扑哧的写啊写。。。。

    第二阶段:集中消灭

    相信不少初学者现在还是处于这个阶段,这阶段的同学们已经被第一阶段折磨怕了。很快就想出了集中消灭相同类型检测的方法。就是写检测函数,如下:

    Code2
    function isEmpty(obj)
    {
        
    if(obj == null || obj.value == "")
            
    return false;
        
    return true;
    }

    function isInt(val)
    {
        
    return /^[1-9]\d$/.test(val);
    }

    function isSafeString(val)
    {
        
    return /^[\u4E00-\u9FA5a-z0-9_]*$/gi.test(val);
    }

    同学们很可能还将上边代码独立成一个公共类,叫Common.js什么的,然后实际检测引用一下,就容易多了:

    Code3
    function SubmitInfo()
    {
        
    var name = document.getElementById("txtName");
        
    var age = document.getElementById("txtAge");
        
    var intro = document.getElementById("txtIntro");
        
    if(!isEmpty(name))
        {
            alert(
    "请输入用户名!");
            
    return false;
        }
        
    if(!isSafeString(name.value))
        {
            alert(
    "用户名只能由中文,英文,数字及下划线组成!");
            
    return false;
        }
        
    if(!isEmpty(age))
        {
            alert(
    "请输入年龄!");
            
    return false;
        }
        
    if(!isInt(age.value))
        {
            alert(
    "年龄必须为正整数!");
            
    return false;
        }
        
    if(!isEmpty(intro))
        {
            alert(
    "请输入自我介绍!");
            
    return false;
        }
        alert(
    "提交成功!");
        
    return true;
    }

    看,不用每次写那些该死检测逻辑了。。要检测什么只要调用一下已经写好的公共检测方法就行了。轻松吧?!不过,还能更轻松吗?当然!请看:

    第三阶段:链式的威力

    看着一大堆if else总是心里觉得不舒服,对吧?一串串的又不是羊肉串,虽然不能吃,也要消灭它们!这时候,是Javascript的prototype出场的时候了。通过扩展prototype,可以获得简洁优雅的代码:

    Code4
    function SubmitInfo()
    {
        
    var name = document.getElementById("txtName");
        
    var age = document.getElementById("txtAge");
        
    var intro = document.getElementById("txtIntro");

        
    if(!name.value.initVerify().isEmpty("请输入用户名!").isSafeString("用户名只能由中文,英文,数字及下划线组成!").verifyComplete())
            
    return false;
        
        
    if(!age.value.initVerify().isEmpty("请输入年龄!").isInt("年龄必须为正整数!").verifyComplete())
            
    return false;
        
        
    if(!intro.value.initVerify().isEmpty("请输入自我介绍!").verifyComplete())
            
    return false;
        
        alert(
    "提交成功!");
        
    return true;
    }

    很简洁吧?相对前边一大串的羊肉串,是不是顺眼多了啊?哦,如何实现?其实很简单:

    Code5
    var validateStatus;
    var validateMessage;

    String.prototype.initVerify 
    = function()
    {
        validateStatus 
    = true;
        validateMessage 
    = "";
        
    return this;
    }

    String.prototype.isEmpty 
    = function(msg)
    {
        
    if(validateStatus)
        {
            
    if(this == null || this == "")
            {
                validateStatus 
    = false;
                validateMessage 
    = msg;
            }
        }
        
    return this;
    }

    String.prototype.isInt 
    = function(msg)
    {
        
    if(validateStatus)
        {
            
    if(!/^[1-9]\d$/.test(this))
            {
                validateStatus 
    = false;
                validateMessage 
    = msg;
            }
        }
        
    return this;
    }

    String.prototype.isSafeString 
    = function(msg)
    {
        
    if(validateStatus)
        {
            
    if(!/^[\u4E00-\u9FA5a-z0-9_]*$/gi.test(this))
            {
                validateStatus 
    = false;
                validateMessage 
    = msg;
            }
        }
        
    return this;
    }

    String.prototype.verifyComplete 
    = function()
    {
        
    if(!validateStatus)
            alert(validateMessage);
        
    return validateStatus;
    }

    怎么样?是不是很简单啊?这个prototype真是一个好东西啊!!链式编程,赞!!呵呵,怎么?你还不满足,代码太长?人心不足啊。我试试吧。。

    第四阶段:自定义属性

    这个阶段的提交函数如下:

    Code6
    function SubmitInfo()
    {
        
    if(!Verify(document.getElementById("txtName"))) return false;
        
    if(!Verify(document.getElementById("txtAge"))) return false;
        
    if(!Verify(document.getElementById("txtIntro"))) return false;
        
        alert(
    "提交成功!");
        
    return true;
    }

    想不通吧?怎么所有检测都一样啊?这不忽悠人吗?哈哈,要实现这个需要在html代码加点酱料:

    Code7
        <div>
            
    <span>请输入用户名,年龄和自我介绍:</span>
            <br />
            <span>用户名:<input type="text" id="txtName" size="20" verifyOptions='{"Empty":{"Flag":false,"Message":"请输入用户名!"},"SafeString":{"Message":"用户名只能由中文,英文,数字及下划线组成!"}}' /></span>
            
    <br />
            <span>年龄:<input type="text" id="txtAge" size="5" verifyOptions='{"Empty":{"Flag":false,"Message":"请输入年龄!"},"Int":{"Message":"年龄必须为正整数!"}}' />岁</span>
            
    <br />
            <span>自我介绍:</span>
            <br />
            <span><textarea id="txtIntro" rows="10" cols="50" verifyOptions='{"Empty":{"Flag":false,"Message":"请输入自我介绍!"}}' ></textarea></span>
            
    <br />
            <span><input type="button" onclick="return SubmitInfo();" value="提交信息" /></span>
        
    </div>

    看到了吧,我们自定义了个叫verifyOption的属性,就是根据它们实现的分别对待的。就好像每个人都有银行卡,但是里面的钱都不一样一样(这个比喻好像比较牵强^_^)

    还是看看Verify函数到底干了什么东西吧:

    Code8
    function Verify(obj)
    {
        
    if(obj.attributes["verifyOptions"== undefined)
        {
            alert(
    "请定义verifyOptions!")
            
    return false;
        }
        
    var options = obj.attributes["verifyOptions"].nodeValue;
        
    if(!options.isEmpty("检测参数不正确!"))
            
    return false;
        
        options 
    = options.parseJSON();
        
        
    if(options.Empty != undefined && options.Empty.Flag == false)
        {
            
    if(!obj.value.isEmpty(options.Empty.Message))
                
    return false;
        }
        
    if(options.Int != undefined)
        {
            
    if(!obj.value.isInt(options.Int.Message))
                
    return false;
        }
        
    if(options.SafeString != undefined)
        {
            
    if(!obj.value.isSafeString(options.SafeString.Message))
                
    return false;
        }
        
    return true;
    }

    就是检测自定义属性里面的设置,根据设置来进行相应检测。这下大家满足了吧?每次检测都一律一句Verify(*)就搞掂了!!QA的MM说检测不对?哦,不用急不用急,修改一下自定义属性verifyOption就好了。哈哈~~~

    第五阶段:可配置

    怎么还有第五阶段?疯狂了疯狂了~~(小子去死!!番茄,鸡蛋都丢上来了~~)唉,大家要注意文明礼貌嘛,丢着我没有关系,丢着花花草草也不好嘛。

    Code9
    <div>
        
    <span>请输入用户名,年龄和自我介绍:</span>
        <br />
        <span>用户名:<input type="text" id="txtName" size="20" /></span>
        
    <br />
        <span>年龄:<input type="text" id="txtAge" size="5" />岁</span>
        
    <br />
        <span>自我介绍:</span>
        <br />
        <span><textarea id="txtIntro" rows="10" cols="50"></textarea></span>
        
    <br />
        <span><input id="btnSubmit" type="button" value="提交信息" /></span>
    </div>

    第五阶段的html代码已经回复清爽了,毕竟自定义属性好像不太友善,不标准!既然不标准就放弃吧!是不是有同学怀疑,这样检测函数岂不是要写更对逻辑,一定比较臃肿吧?好吧,大家看检测函数:

    Code10
    function SubmitInfo()
    {
        
    if(!VerifyComplete())
            
    return false;
        
        alert(
    "提交成功!");
        
    return true;
    }

    不是吧??骗人的吧?但是,事实如此,第五阶段就是这样简洁,这样优雅的实现了和上边几个阶段同样的功能。不相信,那就来看看吧!不过,第五阶段为了方便,引用了JQuery,找东西,它的搜索器还真好用。

    这个阶段我们的检测配置都写到一个变量里面了:

    Code11
    var verifyConfig = [
    {
    "Id":"txtName""Option":{"Empty":{"Flag":false,"Message":"请输入用户名!"},"SafeString":{"Message":"用户名只能由中文,英文,数字及下划线组成!"}}},
    {
    "Id":"txtAge""Option":{"Empty":{"Flag":false,"Message":"请输入年龄!"},"Int":{"Message":"年龄必须为正整数!"}}},
    {
    "Id":"txtIntro""Option":{"Empty":{"Flag":false,"Message":"请输入自我介绍!"}}}]; 

    这个变量我叫配置变量,建议大家将这些变量都放到同一个文件,叫verifyConfig.js?反正我是这么叫的,要修改检测逻辑,就修改这个配置文件就好了,当然,例子由于要强调第五阶段的简洁,就将VerifyComplete()函数参数设置为空,其实它应该有一个参数,用来传入设置变量。这样才通用。

    最后奉上VerifyComplete()函数:

     

    Code12
    function VerifyComplete()
    {
        
    var controls = $(":input");
        
    var verifyFlag = true;
        $.each(controls, 
    function(i, n) {
            
    if(verifyFlag)
                verifyFlag 
    = Verify(n);
        });
        
    return verifyFlag;
    }


    function Verify(obj)
    {
        
    var options;
        $.each(verifyConfig, 
    function(i, n) {
            
    if(n.Id == obj.id)
                options 
    = n.Option;
        });
        
        
    if(options == undefined)
            
    return true;
        
        
    if(options.Empty != undefined && options.Empty.Flag == false)
        {
            
    if(!obj.value.isEmpty(options.Empty.Message))
                
    return false;
        }
        
    if(options.Int != undefined)
        {
            
    if(!obj.value.isInt(options.Int.Message))
                
    return false;
        }
        
    if(options.SafeString != undefined)
        {
            
    if(!obj.value.isSafeString(options.SafeString.Message))
                
    return false;
        }
        
        
    return true;
    }

    斗胆第一次上首页,希望能得到大家指点,进入第六阶段。第六阶段是怎么样?我还真想不到!

    附上上述完整代码:点击下载

    再次浏览自己的代码,发现很多类似:

    WarningCode
    if(xxx)
       
    return true;
    else
       
    return false;

    上边的代码是很笨蛋的.直接一句:

    RightCode
    return xxx;

    或者

    return !xxx;

    就好了..何必大费周章呢.汗死了...自己撞一下墙再反思...哦,还有类似:

    WarningCode
    if(xxx == true)
       

    也是很笨蛋的,只要xxx是bool值.就直接:

    RightCode
    if(xxx)
       

    好了...罚自己面壁思过!

  • 相关阅读:
    UVA 1386 Cellular Automaton
    ZOJ 3331 Process the Tasks
    CodeForces 650B Image Preview
    CodeForces 650A Watchmen
    CodeForces 651B Beautiful Paintings
    CodeForces 651A Joysticks
    HUST 1601 Shepherd
    HUST 1602 Substring
    HUST 1600 Lucky Numbers
    POJ 3991 Seinfeld
  • 原文地址:https://www.cnblogs.com/KenBlove/p/1413746.html
Copyright © 2020-2023  润新知