表单/验证表单——千万不要做一个只会拖控件、“照猫画虎”、copy/paste 程序员

在用 .NET 开发时,随便往页面上拖几个服务器端控件,在控件事件里写点代码处理一下——表单在哪?现在,便利的 IDE 环境越来越弱化“表单”的概念,这个概念的意义更多的是作为一个术语,写在书里,或是用于程序员之间的交流(当使用这个词时,彼此都知道对方在说什么)。当我毕业参加工作时,开发 Web 应用程序已经跟传统方式有很大区别,因此,一直无法体会“表单”。

“表单”概念对 Web 应用程序一直都重要——客户端向服务器端提交(以 get/post 方式)的数据。我是用 .NET 的,.NET 将控件区分成:HTML 控件(客户端控件)和服务器端控件。前者就是传统的、Web 应用程序最初的表单控件。但在 .NET 里,我们可以向任何控件添加 "runat=server" 属性,这样它就会被发送给服务器端。

若你认为,用就行了,想那么多干嘛!我见过太多这样的人,无论是我同学,还是网上,请教问题的态度真得很好——谦虚,礼貌。可抛出的问题,充分说明,他们的基础真的很差……事实说明,千万不要做一个只会拖控件、“照猫画虎”、copy/paste 程序员。

 

本文演示客户端验证表单,通过后发送到服务器端。

本文内容

  • 表单验证
  •      示例1:注册
  •      示例2:购物
  • .NET 表单验证

 

表单验证

示例1:注册

页面完成加载后,初始化页面(表单),添加提交表单前(onsubmit),对表单验证的事件。如果验证成功,则提交;否则,不提交。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link rel="stylesheet" href="css/main.css" />
 
    <script type="text/javascript">
   1:  
   2:         window.onload = initForms;
   3:  
   4:         function initForms() {
   5:             for (var i = 0; i < document.forms.length; i++) {
   6:                 document.forms[i].onsubmit = function() { return validForm(); }
   7:             }
   8:         }
   9:  
  10:         function validForm() {
  11:             var allGood = true;
  12:             var allTags = document.getElementsByTagName("*");
  13:  
  14:             for (var i = 0; i < allTags.length; i++) {
  15:                 if (!validTag(allTags[i])) {
  16:                     allGood = false;
  17:                 }
  18:             }
  19:             return allGood;
  20:  
  21:             function validTag(thisTag) {
  22:                 var outClass = "";
  23:                 var allClasses = thisTag.className.split(" ");
  24:  
  25:                 for (var j = 0; j < allClasses.length; j++) {
  26:                     outClass += validBasedOnClass(allClasses[j]) + " ";
  27:                 }
  28:  
  29:                 thisTag.className = outClass;
  30:  
  31:                 if (outClass.indexOf("invalid") > -1) {
  32:                     invalidLabel(thisTag.parentNode);
  33:                     thisTag.focus();
  34:                     if (thisTag.nodeName == "INPUT") {
  35:                         thisTag.select();
  36:                     }
  37:                     return false;
  38:                 }
  39:                 return true;
  40:  
  41:                 function validBasedOnClass(thisClass) {
  42:                     var classBack = "";
  43:  
  44:                     switch (thisClass) {
  45:                         case "":
  46:                         case "invalid":
  47:                             break;
  48:                         case "reqd":
  49:                             if (allGood && thisTag.value == "") classBack = "invalid ";
  50:                             classBack += thisClass;
  51:                             break;
  52:                         default:
  53:                             if (allGood && !crossCheck(thisTag, thisClass)) classBack = "invalid ";
  54:                             classBack += thisClass;
  55:                     }
  56:                     return classBack;
  57:                 }
  58:  
  59:                 function crossCheck(inTag, otherFieldID) {
  60:                     if (!document.getElementById(otherFieldID)) return false;
  61:                     return (inTag.value == document.getElementById(otherFieldID).value);
  62:                 }
  63:  
  64:                 function invalidLabel(parentTag) {
  65:                     if (parentTag.nodeName == "LABEL") {
  66:                         parentTag.className += " invalid";
  67:                     }
  68:                 }
  69:             }
  70:         }
  71:     
</script>
 
</head>
<body>
    <form action="#">
    <p>
        <label for="userName">
            名字:
            <input type="text" size="30" id="userName" class="reqd" /></label></p>
    <p>
        <label for="passwd1">
            密码:
            <input type="password" id="passwd1" class="reqd" /></label></p>
    <p>
        <label for="passwd2">
            确认密码:
            <input type="password" id="passwd2" class="reqd passwd1" /></label></p>
    <p>
        <input type="submit" value="提交" />&nbsp;<input type="reset" value="重置" /></p>
    </form>
</body>
</html>

运行界面:

ODAK5G%`Z4M`@BP%V5IS%`S

说明:

1,当某个字段不合法时,脚本会在 class 属性里添加 "invalid",在之后的处理中,如果一个标记的 class 属性里包含 "invalid",则改变第一个非法行的式样,并且焦点在那行的 input 标记;

2,页面里,每个标签的 class 属性用于指定表单验证时,使用的规则,用空格分隔,可以在函数 validBasedOnClass 看到。比如,class="reqd" 为应用“必填”规则;class="reqd password1" 为应用两个规则,除了必填外,该标记的值要与 ID为 "password1" 的值相等;

3,第 11 ~  19 行,为验证的主函数。有意思的是,在这个主函数里,内嵌了几个子功能的函数,如 crossCheck、invalidLable等。在示例2,更清楚;

示例2:购物
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link rel="stylesheet" href="css/main.css" />
 
    <script type="text/javascript">
   1:  
   2:         window.onload = initForms;
   3:  
   4:         // 初始化表单
   5:         function initForms() {
   6:             // 本页只有一个form
   7:             for (var i = 0; i < document.forms.length; i++) {
   8:                 document.forms[i].onsubmit = function() { return validForm(); }
   9:             }
  10:             document.getElementById("sunroof").onclick = function() {
  11:                 if (this.checked)
  12:                     document.getElementById("twoDoor").checked = true;
  13:                 else
  14:                     document.getElementById("twoDoor").checked = false;
  15:             }
  16:         };
  17:         // 验证表单
  18:         function validForm() {
  19:             var allGood = true;
  20:             var allTags = document.getElementsByTagName("*");
  21:             for (var i = 0; i < allTags.length; i++) {
  22:                 if (!validTag(allTags[i])) {
  23:                     allGood = false;
  24:                 }
  25:             }
  26:             return allGood;
  27:  
  28:             // 验证标记
  29:             function validTag(thisTag) {
  30:                 var outClass = "";
  31:                 var allClasses = thisTag.className.split(" ");
  32:  
  33:                 for (var j = 0; j < allClasses.length; j++) {
  34:                     outClass += validBasedOnClass(allClasses[j]) + " ";
  35:                 }
  36:  
  37:                 thisTag.className = outClass;
  38:  
  39:                 if (outClass.indexOf("invalid") > -1) {
  40:                     invalidLabel(thisTag.parentNode);
  41:                     thisTag.focus();
  42:                     if (thisTag.nodeName == "INPUT") {
  43:                         thisTag.select();
  44:                     }
  45:                     return false;
  46:                 }
  47:                 return true;
  48:  
  49:                 // 基于 class 验证
  50:                 function validBasedOnClass(thisClass) {
  51:                     var classBack = "";
  52:  
  53:                     switch (thisClass) {
  54:                         case "":
  55:                         case "invalid":
  56:                             break;
  57:                         case "reqd":
  58:                             if (allGood && thisTag.value == "") classBack = "invalid ";
  59:                             classBack += thisClass;
  60:                             break;
  61:                         case "radio":
  62:                             if (allGood && !radioPicked(thisTag.name)) classBack = "invalid ";
  63:                             classBack += thisClass;
  64:                             break;
  65:                         case "isNum":
  66:                             if (allGood && !isNum(thisTag.value)) classBack = "invalid ";
  67:                             classBack += thisClass;
  68:                             break;
  69:                         case "isZip":
  70:                             if (allGood && !isZip(thisTag.value)) classBack = "invalid ";
  71:                             classBack += thisClass;
  72:                             break;
  73:                         case "email":
  74:                             if (allGood && !validEmail(thisTag.value)) classBack = "invalid ";
  75:                             classBack += thisClass;
  76:                             break;
  77:                         default:
  78:                             if (allGood && !crossCheck(thisTag, thisClass)) classBack = "invalid ";
  79:                             classBack += thisClass;
  80:                     }
  81:                     return classBack;
  82:                 }
  83:                 // 用一个字段验证另一个字段
  84:                 function crossCheck(inTag, otherFieldID) {
  85:                     if (!document.getElementById(otherFieldID)) return false;
  86:                     return (inTag.value != "" || document.getElementById(otherFieldID).value != "");
  87:                 }
  88:                 // 单选,必须选一个
  89:                 function radioPicked(radioName) {
  90:                     var radioSet = "";
  91:  
  92:                     for (var k = 0; k < document.forms.length; k++) {
  93:                         if (!radioSet) {
  94:                             radioSet = document.forms[k][radioName];
  95:                         }
  96:                     }
  97:                     if (!radioSet) return false;
  98:                     for (k = 0; k < radioSet.length; k++) {
  99:                         if (radioSet[k].checked) {
 100:                             return true;
 101:                         }
 102:                     }
 103:                     return false;
 104:                 }
 105:                 // 验证数字
 106:                 function isNum(passedVal) {
 107:                     var re = /\d/;
 108:                     return re.test(passedVal);
 109:                 }
 110:                 // 验证邮编
 111:                 function isZip(inZip) {
 112:                     if (inZip == "") {
 113:                         return true;
 114:                     }
 115:                     return (isNum(inZip));
 116:                 }
 117:                 // 正则表达式验证Email
 118:                 function validEmail(email) {
 119:                     var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
 120:                     return re.test(email);
 121:                 }
 122:                 // 标识非法 Label
 123:                 function invalidLabel(parentTag) {
 124:                     if (parentTag.nodeName == "LABEL") {
 125:                         parentTag.className += " invalid";
 126:                     }
 127:                 }
 128:             }
 129:         };
 130:     
</script>
 
</head>
<body>
    <h2 style="text-align: center;">
        挑选汽车</h2>
    <form method="post" action="rec.aspx">
    <p>
        <label for="emailAddr">
            Email地址:
            <input id="emailAddr" type="text" size="30" class="reqd email" />
        </label>
    </p>
    <hr />
    <p>
        <label for="color">
            颜色:
            <select id="color" class="reqd">
                <option value="" selected="selected">选择颜色</option>
                <option value="Red">红色</option>
                <option value="Green">绿色</option>
                <option value="Blue">蓝色</option>
            </select>
        </label>
    </p>
    <hr />
    <p>
        可选:
        <label for="sunroof">
            <input type="checkbox" id="sunroof" value="Yes" />Sunroof(只有2个门)</label>
        <label for="pWindows">
            <input type="checkbox" id="pWindows" value="Yes" />Power Windows</label>
    </p>
    <hr />
    <p>
        <label for="DoorCt">
            门:
            <input type="radio" id="twoDoor" name="DoorCt" value="twoDoor" class="radio" />2
            <input type="radio" id="fourDoor" name="DoorCt" value="fourDoor" class="radio" />4
        </label>
    </p>
    <hr />
    <p>
        <label for="zip">
            填写邮编或选择你最近的供应商:<br />
            邮编:
            <input id="zip" type="text" size="5" maxlength="5" class="isZip dealerList" />
            <select id="dealerList" size="4" class="zip">
                <option value="California--Lemon Grove">California--Lemon Grove</option>
                <option value="California--Lomita">California--Lomita</option>
                <option value="California--Long Beach">California--Long Beach</option>
                <option value="California--Los Alamitos">California--Los Alamitos</option>
                <option value="California--Los Angeles">California--Los Angeles</option>
            </select>
        </label>
    </p>
    <hr />
    <p>
        <input type="submit" value="提交" />&nbsp;<input type="reset" value="重置" /></p>
    </form>
</body>
</html>

运行界面:

FM5%R@DW[U]`6$$92S8}@]A

说明:

1,示例2 与示例1 差不多;

2,validForm 函数里内嵌了好几个功能性函数。这点比较有意思。

   1: function validForm() {
   2:     var allGood = true;
   3:     var allTags = document.getElementsByTagName("*");
   4:     // 调用函数 validTag
   5:     // ......
   6:  
   7:     return allGood;
   8:  
   9:     function validTag(thisTag) {
  10:         var outClass = "";
  11:         var allClasses = thisTag.className.split(" ");
  12:         // 调用函数 validBasedOnClass
  13:         // ......
  14:         for (var j = 0; j < allClasses.length; j++) {
  15:             outClass += validBasedOnClass(allClasses[j]) + " ";
  16:         }
  17:  
  18:         thisTag.className = outClass;
  19:  
  20:         if (outClass.indexOf("invalid") > -1) {
  21:             // 调用函数 invalidLabel
  22:             // ......
  23:             return false;
  24:         }
  25:         return true;
  26:  
  27:         function validBasedOnClass(thisClass) {
  28:             // 使用 all Good 和 thisTag 变量
  29:             // 以及调用函数 crossCheck radioPicked isNum isZip validEmail
  30:             // ......
  31:         }
  32:  
  33:         function crossCheck(inTag, otherFieldID) {
  34:             // ......
  35:         }
  36:  
  37:         function radioPicked(radioName) {
  38:             // ......
  39:         }
  40:  
  41:         function isNum(passedVal) {
  42:             // ......
  43:         }
  44:  
  45:         function isZip(inZip) {
  46:             // ......
  47:         }
  48:         function validEmail(email) {
  49:             // ......
  50:         }
  51:         // 标识非法 Label
  52:         function invalidLabel(parentTag) {
  53:             // ......
  54:         }
  55:     }

在上面的结构,内嵌函数使用了它外层的变量。比如,定义在 validForm 里的 allGood 变量,在 validBasedOnClass 里使用了。这是 JavaScript 的一个特色,可以缓存数据,你可以查匿名函数的相关资料。

 

.NET 表单验证

上面表单验证,比如验证Email 地址,若在 .NET 里,可以用如下简单方式:

<asp:TextBox ID="emailAddr" runat="server"></asp:TextBox><br />
<asp:RegularExpressionValidator ValidationExpression="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$"
    ID="RegularExpressionValidator1" ControlToValidate="emailAddr" runat="server"
    ErrorMessage="Email 地址非法"></asp:RegularExpressionValidator>

运行界面:

9Y8OL8)6XQ0M3RDS8UH7J8M

 

下载 Demo

 

本文版权归作者和博客园,欢迎转载。若要转载,请在文章注明原文出处。

posted @ 2011-10-05 14:45  船长&CAP  阅读(895)  评论(2编辑  收藏  举报
免费流量统计软件