第2章 在Web表单中使用HTML 5

本章内容

案例3:用结构元素制作Web应用程序中的菜单

案例4:综合运用HTML5、jQuery与ASP.NET构建Web应用程序

本章小结

本章通过两个案例来介绍如何在Web表单中使用HTML 5的新增结构元素和新增表单元素,以及怎样编写服务器端的脚本语言将用户在HTML 5新增表单元素中的输入内容保存到服务器端的数据库中。

本章首先介绍一个使用HTML 5、CSS 3样式和jQuery脚本制作的比较典型的Web应用中的菜单。接下来重点介绍一个使用HTML 5及其新增表单元素、CSS 3样式、jQuery脚本以及ASP.NET服务器端脚本开发的Web应用中的一个信息录入页面。该页面中有一个显示所有录入信息的一览表,用户录入一条信息后,该数据在数据库中保存完毕后立即显示在一览表中。该页面使用一个目前在Web网站或Web应用广泛使用的、使用jQuery脚本开发的jQuery验证器。该验证器在客户端对用户输入的各种数据(包括用户在HTML 5新增的各种表单元素中输入的各种数据)进行验证,验证通过后再将数据提交到服务器端进行保存。

2.1 案例3:用结构元素制作Web应用程序中的菜单

2.1.1 页面显示效果

在本案例中,我们将利用HTML 5的结构元素来制作一个Web应用程序中比较常见的菜单。该Web应用程序在浏览器中的总体效果如图2-1所示。

图2-1 Web应用程序的总体效果

这个Web应用程序的页面框架由三个子页面组成,分别为顶部的工具栏菜单页面、左边的主菜单页面与右边的应用程序主体页面。

这里只关注左边的应用程序主菜单页面,该页面打开时在浏览器中的显示效果如图2-2所示。

图2-2 主菜单页面

这个菜单有七个主菜单项,其中第三个菜单项到第七个菜单项没有子菜单,单击菜单项后应用程序右边的主体页面中会根据单击的菜单项显示不同的页面,而第一个菜单项和第二个菜单项均有子菜单项,

单击主菜单项时页面中会显示该主菜单项下面的子菜单项,如图2-3和图2-4所示,再次单击该主菜单项时其子菜单项会被隐藏。

图2-3 单击“系统信息管理”主菜单项时将显示其子菜单项

图2-4 单击“基础信息管理”主菜单项时将显示其子菜单项

同样地,单击这些子菜单项后应用程序右边的主体页面中会根据单击的子菜单项显示不同的页面。

2.1.2 代码剖析

接下来先看一下这个菜单页面的HTML 5代码部分。在该页面中,由于各菜单项中均有链接元素a,单击该菜单项后,右边的主体页面会由一个页面切换到另一个页面,所以可以将这些菜单视为一个链接组,并将其放置在nav元素中。在nav元素中,再由ul列表元素及其li列表项目元素来具体显示每一个菜单项。

这个菜单页面的HTML 5代码如代码清单2-1所示。

代码清单2-1 菜单页面的HTML 5代码

    <!DOCTYPE html>
    <meta charset=utf-8 />
    <title>HTML 5版菜单</title>
    <body onload="init()">
        <nav id="nav">
        <ul>
          <li id="first"></li>
          <li><img src="images/xtgl.gif" onclick="nav_fill1()"/></li>
          <li>
            <nav id="submenu1">
                <ul>
                    <li>
                        <a href="add_user.html"   target="mainFrame">
                            用户权限管理
                        </a>
                    </li>
                    <li>
                        <a href="data_security.html"   target="mainFrame">
                            数据安全管理
                        </a>
                    </li>
                    <li>
                        <a href="soft_update.html"   target="mainFrame">
                            软件升级管理
                        </a>
                    </li>
                </ul>
            </nav>
          </li>
          <li><img src="images/jcxx.gif" onclick="nav_fill2()"/></li>
          <li>
            <nav id="submenu2">
                <ul>
                    <li>
                        <a href="add_city.html"   target="mainFrame">
                            城市管理
                        </a>
                    </li>
                    <li>
                        <a href="add_store"   target="mainFrame">
                            仓库管理
                        </a>
                    </li>
                    <li>
                    <a href="add_material.html"   target="mainFrame">
                        材料管理
                        </a>
                    </li>
                </ul>
            </nav>
          </li>
          <li><a href="qpxx.html"><img src="images/qpxx.gif"/></a></li>
          <li><a href="ccgl.html"><img src="images/ccgl.gif"/></a></li>
          <li><a href="qpcz.html"><img src="images/qpcz.gif"/></a></li>
          <li><a href="cccz.html"><img src="images/cccz.gif"/></a></li>
          <li><a href="qpjy.html"><img src="images/qpjy.gif"/></a></li>
        </ul>
        </nav>
    </body>
    </html>

这个菜单页面中使用的样式代码如代码清单2-2所示。

代码清单2-2 菜单页面所使用的样式代码

    <style type="text/css">
    body {
        margin:0px;
    }
    nav ul li{
        list-style:none;
        width:195px;
        line-height:10px;
    }
    nav ul li img{
        width:195px;
        height:28px;
        cursor:pointer;
    }
    nav ul li#first{
        height:6px;
        background:url(images/left_title_bg.gif);
    }
    nav ul li ul {
        display:inline;
        padding:0px;
    }
    nav ul li ul li{
        height:20px;
        background-color:#AEE4EE;
        font-size: 12px;
        color: #333333;
        text-align: center;
        width:195px;
    }
    nav ul li ul li a{
        font-size: 12px;
        color: #333333;
        text-decoration: none;
    }
    </style>

最后来看一下该菜单页面中使用的JavaScript脚本代码部分。该菜单页面使用的脚本代码比较简单,其功能为打开页面时将第一个主菜单项与第二个主菜单项下的子菜单项隐藏起来,单击第一个主菜单项或第二个主菜单项时将该主菜单项下的子菜单项显示出来,再次单击时将该主菜单项下的子菜单项隐藏起来,代码如代码清单2-3所示。

代码清单2-3 菜单页面中使用到的脚本代码

    <script>
    function init()
    {
        document.getElementById("submenu1").hidden=true;
        document.getElementById("submenu2").hidden=true;
    }
    function nav_fill1()
    {
        if(document.getElementById("submenu1").hidden===true)
          document.getElementById("submenu1").hidden=false;
        else
          document.getElementById("submenu1").hidden=true;
    }
    function nav_fill2()
    {
        if(document.getElementById("submenu2").hidden===true)
          document.getElementById("submenu2").hidden=false;
        else
          document.getElementById("submenu2").hidden=true;
    }
    </script>

2.2 案例4:综合运用HTML 5、jQuery与ASP.NET构建Web应用程序

2.2.1 案例概述

在本案例中,我们将制作Web应用程序中的一个数据输入页面。该页面主要在企业内部的操作人员输入商业订单或企业订单时使用,故又叫订单输入页面。该页面分为上下两个部分,用户在页面上半部分的Web表单中输入一条数据,然后单击追加按钮,该数据将会在页面下半部分的一览表中即时显示出来,表示数据追加成功。

2.2.2 页面显示效果

首先来看一下该页面在浏览器中的显示效果,如图2-5所示。

图2-5 页面在浏览器中的显示效果

该页面具有自动验证功能,当用户在某个文本框中输入无效数据后单击追加按钮时,页面上自动显示验证错误提示信息,阻止表单向服务器端的提交,如图2-6所示。

图2-6 数据无效时显示验证错误信息

当用户修改该数据使其能够通过验证后,单击追加按钮,该数据将被保存到数据库中,然后即时显示在页面下端的数据一览表中,如图2-7所示。

图2-7 数据通过验证后单击追加按钮时即被显示到订单信息一览表中

该页面的结构比较简单,有上下两个section元素,如图2-8所示。

图2-8 订单输入页面的结构图

这两个section元素内部开头处都没有使用header元素,而是直接使用标题元素h5来显示上下两个区域的标题文字。

2.2.3 案例知识点

本案例主要涉及以下几方面的知识点:

HTML 5中新增表单元素的作用以及使用方法

jQuery脚本代码的编写方法

ASP.NET服务器端脚本代码的编写方法

HTML 5中新增表单元素的作用以及使用方法的有关知识,可以参照笔者所著的《HTML 5与CSS 3权威指南》一书,此处不再赘述。

关于脚本代码以及ASP.NET服务器端脚本代码的编写方法,均不在本书所介绍的范围之中,故不做介绍。

这里对本案例所使用的一个jQuery验证器插件—jQuery-validation插件进行详细介绍,使读者对这个插件有一个比较全面的认识。

jQuery-validation插件可以从官方网站(http://cloud.github.com/downloads/posabsolute/jQuery-Validation-Engine/formValidator.2.1.zip)上下载。当用户提交表单时该插件能够根据用户指定的验证规则对向表单中输入的元素内容进行验证,当验证没通过时给出具有悬浮效果的验证错误提示信息,如图2-9所示。

图2-9 jQuery验证插件的具有悬浮效果的验证错误提示信息

在这个页面中,由于使用了jQuery验证插件,因此当用户提交表单时,会对表单中所有元素进行验证。当验证没有通过时,给出具有悬浮效果的验证错误提示信息,如“2.2.2页面显示效果”中的图2-6所示。

从官方网站上下载的压缩包中有很多文件,主要用到以下三个文件。

(下载文件夹)\ formValidator.2.1\js\jquery.validationEngine.js(插件主文件)

(下载文件夹)\ formValidator.2.1\js\languages\jquery.validationEngine-en.js(供用户添加验证规则的js文件,内置基本验证规则)

(下载文件夹)\ formValidator.2.1\ css\ validationEngine. jquery.css(验证插件所使用的样式表文件)

为了在页面中使用这个jQuery插件,我们需要执行以下几个步骤。

1)在页面中加入如下所示的jQuery脚本代码。

    $(function () {
    $("#form1").validationEngine();
    });

2)在需要验证的元素中添加class属性。例如,为了验证页面中的“订单编号”文本框,我们为它添加了如下的class属性。

    <input type="text" id="tbxCode" name="tbxCode" maxlength="8"
    class="validate[required]" placeholder="必须输入一个不存在的订单编号"
    autofocus    required/>

本例使用了如下几个验证规则,各规则之间以“,”分隔。

required:必须在该元素中输入内容。

optional:该元素内容可以为空。之所以使用该验证规则是因为它之后往往具有其他验证规则,如果元素内容不为空则必须满足其他验证规则。如果不加入optional规则而直接书写验证规则表示元素内容必须满足验证规则,而且该元素内容不能为空。

custom[date] :该元素中内容必须为有效日期。

custom[integer] :该元素中内容必须为整数。

custom[number] :该元素中内容必须为有效数值(允许带小数点)。

custom[email] :该元素中内容必须为有效E-mail邮件地址。

除了以上本页面中使用到的规则之外,验证插件中还自带如下几个规则。

minSize:该元素中至少必须输入的字符数。

maxSize:该元素中最多允许输入的字符数。

min:该元素中输入的数值必须大于等于指定数值。

max:该元素中输入的数值必须小于等于指定数值。

past:该元素中输入的日期必须早于或等于某个指定日期。

future:该元素中输入的日期必须晚于或等于某个指定日期。

maxCheckbox:最多允许几个复选框处于选取状态。

minCheckbox:最少需要几个复选框处于选取状态。

equals:用于确认所验证的元素中的内容必须等于某个指定元素中的内容。可用于确认密码等场合。

telephone:该元素中内容必须为有效的电话号码。

ipv4:该元素中内容必须为有效的IP地址。

url:该元素中内容必须为有效的网址。

onlyNumberSp:该元素中只能输入数字。

onlyLetterSp:该元素中只能输入字母。

onlyLetterNumber:提交时该元素中内容只能为字母或数字,不允许输入其他字符。

ajaxUserCall:需要开发者修改其中默认设置的file属性与extraData属性,用于向某个网址执行ajax提交,验证用户名是否有效。

ajaxUserCallPhp:需要开发者修改其中默认设置的file属性与extraData属性,用于向某个文件执行ajax提交,验证用户名是否有效。可根据文件类型修改这个验证规则的验证名,例如,向asp文件执行ajax提交时,可改成ajaxUserCallAsp。

ajaxNameCall:需要开发者修改其中默认设置的file属性,用于向某个网址执行ajax提交,验证名字是否已被使用。

ajaxNameCallPhp:需要开发者修改其中默认设置的file属性,用于向某个文件执行ajax提交,验证名字是否已被使用。可根据文件类型修改这个验证规则的验证名,例如,向asp文件执行ajax提交时,可改成ajaxNameCallAsp。

后四个验证规则用于ajax提交,以下为一个典型的用户登录时所使用的用户名文本框。

    <input type="text" id="userName" name="userName" maxlength="20"
    class="validate[ajax[ajaxUser]]"

我们可以使用ajaxUser验证规则对用户名进行验证。该验证规则定义如下。

    "ajaxUser":{
    /*file属性值为后台提交的脚本文件,插件会提交三个参数:
    validateError,validateId,validateValue,后台脚本直接request即可*/
    "file":"validateUser.php",
    "extraData":"name=eric",
    "alertTextOk":"* This username is available",
    "alertTextLoad":"* Loading, please wait",
    "alertText":"* This username is already taken"},

我们可以将“validateUser.php”修改为任何需要验证的用户后台文件,但是该后台脚本文件必须返回固定格式的json数据。官方网站提供的作为示例的php文件内容如代码清单2-4所示。

代码清单2-4 官方网站提供的用于验证用户名的php文件

    <?php
    /* 获取提交值 */
    $validateValue=$_GET['fieldValue'];
    $validateId=$_GET['fieldId'];
    $validateError= "This username is already taken";
    $validateSuccess= "This username is available";
    /* 返回值 */
    $arrayToJs = array();
    $arrayToJs[0] = $validateId;
    if($validateValue =="duncan"){             // 验证通过
      $arrayToJs[1] = true;                    // 返回TRUE
      echo json_encode($arrayToJs);            // 返回成功时的json数组
    }
    else//验证失败
    {
      for($x=0;$x<1000000;$x++){
        if($x == 990000){
              $arrayToJs[1] = false;
              echo json_encode($arrayToJs);    // 返回失败时的json数组
      }
    }
    }
    ?>

开发者可根据需要将该文件名和文件内容修改成其他语言和验证逻辑对应的验证文件。

3)根据需要修改验证方法。

在页面中可以不使用默认的插件,而使用如下代码来修改验证插件对元素内容的验证方法。例如,验证插件的默认验证时机为控件失去焦点时触发验证,用户可以在页面中加入如下代码,在提交控件时进行验证。

    $(function () {
        $("#form1").validationEngine({
            //inlineValidation: true
            inlineValidation: true,//修改为false
            success : false,
            failure:function{callFailFunction{}}
        });
    });

或者加入如下代码,在其他的时机进行验证。

    $(function () {
        $("#form1").validationEngine({
            //validationEventTriggers:"focusout",
            validationEventTriggers:"keyup",,//修改为按键后即执行验证
            success : false,
            failure:function{callFailFunction{}}
        });
    });

也可以加入如下代码,修改验证错误提示信息与被验证元素的位置关系。

    $(function () {
      $("#form1").validationEngine({
      //promptPosition: "topRight",//验证错误提示信息位于元素的右上角
      //修改为位于元素的右下角,
      //可设定值为topLeft, topRight, bottomLeft, centerRight,bottomRight
      validationEventTriggers:"bottomRight",,
      success : false,
      failure:function{callFailFunction{}}
      });
    });

4)添加中文版验证错误提示信息文件。

由于从官方网站上下载的压缩包中的验证错误提示信息文件[在(下载文件夹)\formValidator.2.1\js\languages]中,没有中文版的验证错误提示信息文件,因此需要手工添加中文版的验证错误提示信息文件。笔者添加的中文版验证错误提示信息文件如代码清单2-5所示。

代码清单2-5 笔者添加的中文版验证错误提示信息文件

    (function($){
        $.fn.validationEngineLanguage = function(){
        };
        $.validationEngineLanguage = {
            newLang: function(){
                $.validationEngineLanguage.allRules = {
                    "required": { // 追加正则表达式作为验证规则
                        "regex": "none",
                        "alertText": "* 必须输入内容",
                        "alertTextCheckboxMultiple": "* 必须选择一个选项",
                        "alertTextCheckboxe": "* 必须为选取状态"
                    },
                    "minSize": {
                        "regex": "none",
                        "alertText": "* 至少必须输入 ",
                        "alertText2": " 个字符"
                    },
                    "maxSize": {
                        "regex": "none",
                        "alertText": "* 最多允许输入 ",
                        "alertText2": " 个字符"
                    },
                    "min": {
                        "regex": "none",
                        "alertText": "* 数字必须大于等于 "
                    },
                    "max": {
                        "regex": "none",
                        "alertText": "* 数字必须小于等于 "
                    },
                    "past": {
                        "regex": "none",
                        "alertText": "* 日期必须早于 "
                    },
                    "future": {
                        "regex": "none",
                        "alertText": "* 日期必须晚于 "
                    },
                    "maxCheckbox": {
                        "regex": "none",
                        "alertText": "* 超出允许选取的项目个数"
                    },
                    "minCheckbox": {
                        "regex": "none",
                        "alertText": "* 请至少选择 ",
                        "alertText2": " 个选项"
                    },
                    "equals": {
                        "regex": "none",
                        "alertText": "* 输入的内容不一致"
                    },
                    "phone": {
                        "regex":/^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}
                        [\)])?([0-9\.\-\/]{3,20})((x|ext|extension)[ ]
                        ?[0-9]{1,4})?$/,
                        "alertText": "* 请输入有效的电话号码"
                    },
                    "email": {
                        "regex": /^([A-Za-z0-9_\-\.\'])+\@([A-Za-z0-9_\-\.])
                        +\.([A-Za-z]{2,6})$/,
                        "alertText": "* 请输入有效的邮件地址"
                    },
                    "integer": {
                        "regex": /^[\-\+]?\d+$/,
                        "alertText": "* 请输入一个整数"
                    },
                    "number": {
                        "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))
                        ?|([\.,]([0-9]+))?)$/,
                        "alertText": "* 请输入一个数值"
                    },
                    "date": {
                        "regex":/^\d{4}[\/\-](0?[1-9]|1[012])
                        [\/\-](0?[1-9]|[12][0-9]|3[01])$/,
                        "alertText": "* 日期格式不正确,必须为YYYY-MM-DD格式"
                    },
                    "ipv4": {
                        "regex":/^((([01]?[0-9]{1,2})|(2[0-4][0-9])
                        |(25[0-5]))[.]){3} (([0-1]?[0-9]{1,2})|(2[0-4][0-9])
                        |(25[0-5]))$/,
                        "alertText": "* 请输入一个有效的IP地址"
                    },
                    "url": {
                        "regex":/^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[
                        \u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})
                        |[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]
                        \d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])
                        \.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d
                        \d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-
                        \uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-
                        \uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF
                        \uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF
                        \uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-
                        \uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-
                        \uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[
                        \u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[
                        \u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:
                        \d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-
                        \uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]
                        |:|@)+(\/(([a-z]| \d|-|\.|_|~|[\u00A0-\uD7FF\uF900-
                        \uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*
                        \+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-
                        \uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'
                        \(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|
                        \d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])
                        |(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/,
                        "alertText": "* 请输入一个有效的网址"
                    },
                    "onlyNumberSp": {
                        "regex": /^[0-9\ ]+$/,
                        "alertText": "* 只能输入数字"
                    },
                    "onlyLetterSp": {
                        "regex": /^[a-zA-Z\ \']+$/,
                        "alertText": "* 只能输入字母"
                    },
                    "onlyLetterNumber": {
                        "regex": /^[0-9a-zA-Z]+$/,
                        "alertText": "* 只能输入数字或字母"
                    },
                    "ajaxUserCall": {
                        "url": "ajaxValidateFieldUser",
                        "extraData": "name=eric",
                        "alertText": "* 用户名已被使用",
                        "alertTextLoad": "* 正在验证,请稍候"
                    },
            "ajaxUserCallPhp": {
                        "url": "phpajax/ajaxValidateFieldUser.php",
                        "extraData": "name=eric",
                        "alertTextOk": "* 用户名有效",
                        "alertText": "* * 用户名已被使用",
                        "alertTextLoad": "* 正在验证,请稍候"
                    },
                    "ajaxNameCall": {
                        "url": "ajaxValidateFieldName",
                        "alertText": "* 这个名字已被使用",
                        "alertTextOk": "* 这个名字可以使用",
                        "alertTextLoad": "* 正在验证,请稍候"
                    },
            "ajaxNameCallPhp": {
                        "url": "phpajax/ajaxValidateFieldName.php",
                        "alertText": "* 这个名字已被使用",
                        "alertTextLoad": "* 正在验证,请稍候"
                    },
                    "validate2fields": {
                        "alertText": "* 请输入 HELLO"
                    }
                };
            }
        };
        $.validationEngineLanguage.newLang();
    })(jQuery);

2.2.4 代码剖析

1. HTML 5页面代码

接下来具体看一下该页面的HTML 5页面代码部分,该页面为一个商业订单数据的输入页面,分为上下两部分,分别存放在两个section元素中,两个section元素的标题分别为“编辑订单信息”与“订单信息一览表”。在第一个section元素中,存放了一个供用户输入订单数据的表单,在该表单内使用了很多HTML 5中新增的表单元素。在第二个section元素中,存放了一张用户输入的订单数据一览表,页面打开时,该一览表中显示数据库中保存的所有订单数据,用户输入一条订单数据并单击保存按钮后,该表单被提交到服务器端,用户输入的这条订单数据被保存到数据库中,然后该页面被刷新,一览表中即时显示用户输入的这条数据。

该页面中所有控件的信息如表2-1所示。

表2-1 页面中所有控件的信息

(续)

在查看这段HTML 5页面代码之前,要注意的是,本页面中很多文本框使用了一个特殊的class属性,在“2.2.3案例知识点”中已介绍过,这些class属性是使用jQuery验证器插件对表单中的各元素内容进行验证时所使用的各种验证规则,这里不再赘述。

该页面中的HTML 5页面代码如代码清单2-6所示。

代码清单2-6 页面中的HTML 5页面代码

    <%@ Page Title="订单信息" Language="C#"   AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="HTML5TEST.Default" %>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>订单信息</title>
    <body onload="init()">
    <form id="form1"   method="post" runat=server>
    <section>
        <h5>编辑订单信息</h5>
        <ul>
            <li>
              <ul>
                    <li id="title_1"><label for="tbxCode">订单编号</label></li>
                    <li id="content_1">
                        <input type="text" id="tbxCode" name="tbxCode"
                        maxlength="8"   class="validate[required]"
                        placeholder="必须输入一个不存在的订单编号" autofocus
                        required/>
                    </li>
                    <li id="title_2"><label for="tbxDate">订单日期</label></li>
                    <li id="content_2">
                        <input type="date" id="tbxDate" name="tbxDate"
                        maxlength="10" class="validate[required,custom[date]]"
                        placeholder="必须输入一个有效的日期"   required/>
                    </li>
                    <li id="title_3">
                        <label for="tbxGoodsCode">商品编号</label>
                    </li>
                    <li id="content_3">
                        <input type="text"   id="tbxGoodsCode" name="tbxGoodsCode"
                        maxlength="12"   class="validate[required]"
                        placeholder="必须输入商品编号" required/>
                    </li>
                </ul>
              </li>
            <li>
            <ul>
              <li id="title_4">
                  <label for="tbxBrandName">
                    &nbsp;&nbsp;&nbsp;&nbsp;
                  </label>
              </li>
              <li id="content_4">
                  <input   type="text" id="tbxBrandName" name="tbxBrandName"
                  maxlength="50"/>
              </li>
              <li id="title_5">
                  <label for="tbxNum">&nbsp;&nbsp;&nbsp;&nbsp;</label>
              </li>
              <li id="content_5">
                  <input type="number" id="tbxNum" name="tbxNum"
                  maxlength="6" value="0"
                  class="validate[required,custom[integer]]"
                  placeholder="必须输入一个整数值"/>
              </li>
              <li id="title_6">
                  <label for="tbxPrice">&nbsp;&nbsp;&nbsp;&nbsp;</label>
              </li>
              <li id="content_6">
                  <input type="text" id="tbxPrice" name="tbxPrice"
                  maxlength="6" value="0"
                  class="validate[required,custom[number]]"
                  placeholder="必须输入一个有效的单价"/>
              </li>
          </ul>
      </li>
      <li>
          <ul>
                    <li id="title_7">
                        <label for="tbxMoney">
                          &nbsp;&nbsp;&nbsp;&nbsp;
                        </label>
                    </li>
                    <li id="content_7">
                        <input   type="text" id="tbxMoney" name="tbxMoney"
                        readonly="readonly"   value="0"/>
                    </li>
                    <li id="title_8">
                        <label for="tbxPersonName">&nbsp;&nbsp;</label>
                    </li>
                    <li id="content_8">
                        <input type="text" id="tbxPersonName"
                        name="tbxPersonName" maxlength="20"/>
                    </li>
                    <li id="title_9">
                        <label for="tbxEmail">负责人Email</label>
                    </li>
                    <li id="content_9">
                        <input type="email" id="tbxEmail" name="tbxEmail"
                        maxlength="20" class="validate[optional,custom[email]]"
                        placeholder="请输入一个有效的邮件地址"/>
                    </li>
                </ul>
            </li>
        </ul>
        <div id="buttonDiv">
            <asp:Button ID="btnNew"    runat="server" Text="新增"
            onclick="btnNew_Click"/>
            <asp:Button ID="btnAdd"   runat="server" Text="追加"
            onclick="btnAdd_Click"/>
            <asp:Button ID="btnUpdate"   runat="server" Text="修改" Enabled=false
            onclick="btnUpdate_Click"/>
            <asp:Button ID="btnDelete"   runat="server" Text="删除" Enabled=false
            onclick="btnDelete_Click"/>
            <asp:Button ID="btnClear"   runat="server" Text="清除"   Enabled=false
            onclick="btnClear_Click"/>
        </div>
    <section>
    <section>
        <h5>订单信息一览表</h5>
        <div id="infoTable">
            <asp:datagrid id="datatable"
                runat="server"
                Width="100%"
                BorderWidth="0px"
                AutoGenerateColumns="false"
                CellPadding="1"
                CellSpacing="1"
                AllowPaging="True"
                PageSize ="10"
                EnableViewState="true"
                OnPageIndexChanged="datatable_PageIndexChanged"
                OnItemCommand="datatable_ItemCommand">
                <Columns>
                    <asp:BoundColumn DataField="code" HeaderText="订单编号"/>
                    <asp:BoundColumn DataField="orderDate"
                    HeaderText="订单日期"/>
                    <asp:BoundColumn DataField="goodsCode"
                    HeaderText="商品编号"/>
                    <asp:BoundColumn DataField="brandName" HeaderText="商标"/>
                    <asp:BoundColumn DataField="num" HeaderText="数量"/>
                    <asp:BoundColumn DataField="price" HeaderText="单价"/>
                    <asp:BoundColumn DataField="money" HeaderText="金额"/>
                    <asp:BoundColumn DataField="personName" HeaderText="负责人"/>
                    <asp:BoundColumn DataField="email" HeaderText="负责人Email"/>
                    <asp:ButtonColumn CommandName ="select" HeaderText="编辑"
                    Text ="编辑"/>
                </Columns>
                <PagerStyle HorizontalAlign="Right" Width="100%"
                Mode="NumericPages" Position="Bottom" Wrap="false" />
                <SelectedItemStyle BackColor="Blue" ForeColor="White" />
            </asp:datagrid>
        </div>
    </section>
    </form>
    </body>
    </html>

2. 样式代码

在这个页面中,使用了很多CSS3样式,下面先对这些CSS3样式进行讲解。

在表单部分,使用ul列表中嵌套ul列表的形式对表单进行布局。其中,内层的ul列表用于横向布局,每行显示三个label标签与三个TextBox文本框,外层的ul列表用于竖向布局,将内层的ul列表进行竖向排列。这两个ul列表的样式代码如下所示。

    //外层的ul列表用于竖向布局
    ul{
        width:100%;
        display: -moz-box;
        display: -webkit-box;
        -moz-box-orient: vertical;
        -webkit-box-orient:vertical;
        margin:0px;
        padding:0px;
    }
    //内层的ul列表用于横向布局
    ul li ul{
        display: -moz-box;
        display: -webkit-box;
        -moz-box-orient: horizontal;
        -webkit-box-orient:horizontal;
    }

将每个li列表项目元素的list-style属性设为none,使其默认列表项目的项目编号不被显示。代码如下所示。

    li{
        list-style:none;
    }

使用[att^=val] 属性选择器分别控制表单中每个用于放置标签的li列表项目元素的样式与每个用于放置文本框的li列表项目元素的样式。例如,如下HTML代码,表单中所有放置标签的li列表项目元素的id都是以“title”文字开头的,放置文本框的li列表项目元素的id都是以“content”文字开头的。

    <li id="title_1"><label for="tbxCode">订单编号</label></li>
    <li id="content_1">
        <input type="text" name="tbxCode" id="tbxCode" maxlength="8"
        class="validate[required]" placeholder="必须输入订单编号" required
        autofocus/>
    </li>

使用如下样式代码。

    <li[id^=title]{
        font-size: 12px;
        color: #333333;
        background-color:#E6E6E6;
        text-align:right;
        padding-right:5px;
        width:120px;
    }
    li[id^=content]{
        height:22;
        background-color:#FAFAFA;
        text-align:left;
        padding-left:2px;
        width:220px;
    }

使用E: read-only伪类选择器控制表单中文本框处于只读状态时的样式,代码如下所示。

    input:read-only{
        background-color:yellow;
    }
    //Firefox浏览器中需使用-moz-前缀
    input:-moz-read-only{
        background-color:yellow;
    }

使用属性选择器控制所有按钮样式,代码如下所示。

    input[type="submit"]{
        font-size: 12px;
        width: 68px;
        height: 20px;
        cursor: hand;
        border:none;
        font-family:宋体;
        background-color:White;
        background-image:   url(images/but_bg.gif);
        color: white;
    }

对于ASP.NET的DataGrid控件,其样式不在页面上书写,而是在样式代码中使用CSS3样式代码统一书写,同时使用nth-child(even)选择器与nth-child(odd)选择器分别控制一览表中所有偶数行与奇数行的背景色与文字颜色。使用nth-child(1)选择器单独控制标题行的背景色与文字颜色。使用nth-last-child(1)选择器单独控制一览表中最后一列(编辑按钮列)的宽度。代码如下所示。

    div#infoTable   table tr:nth-child(odd){
        background-color:#E6E6E6;
        color: #333333;
    }
    div#infoTable   table tr:nth-child(even){
        background-color:#fafafa;
        color: black;
    }
    div#infoTable   table tr:nth-child(1){
        background-color:#7088AD;
        color: #FFFFFF;
    }
    div#infoTable   table th:nth-last-child(1){
        width: 15%;
    }

该页面的完整样式代码如代码清单2-7所示。

代码清单2-7 页面的完整的样式代码

    <style type ="text/css">
    body {
        margin-left: 0px;
        margin-top: 0px;
    }
    h5{
        margin:0px;
    }
    ul{
        width:100%;
        display: -moz-box;
        display: -webkit-box;
        -moz-box-orient: vertical;
        -webkit-box-orient:vertical;
        margin:0px;
        padding:0px;
    }
    li{
        list-style:none;
    }
    ul li ul{
        display: -moz-box;
        display: -webkit-box;
        -moz-box-orient: horizontal;
        -webkit-box-orient:horizontal;
    }
    header{
        font-size: 14px;
        font-weight: bold;
        color:white;
        background-color:#7088AD;
        text-align:left;
        padding-left:10px;
        display:block;
        width:100%;
    }
    li[id^=title]{
        font-size: 12px;
        color: #333333;
        background-color:#E6E6E6;
        text-align:right;
        padding-right:5px;
        width:120px;
    }
    li[id^=content]{
        height:22;
        background-color:#FAFAFA;
        text-align:left;
        padding-left:2px;
        width:220px;
    }
    span{
        color: #ff0000;
    }
    input{
        width: 95%;
        border-style: solid;
        border-top-color: #426C7C;
        border-right-color: #CCCCCC;
        border-bottom-color: #CCCCCC;
        border-left-color: #426C7C;
        border-width: 1px;
        border:1px solid #0066cc;
        height: 18px;
    }
    input:read-only{
        background-color:yellow;
    }
    input:-moz-read-only{
        background-color:yellow;
    }
    input#tbxNum{
        text-align:right;
    }
    input#tbxPrice{
        text-align:right;
    }
    input#tbxMoney{
        text-align:right;
    }
    #tbxBrand,#tbxPerson,#tbxProduct{
        width:20px;
    }
    div{
        text-align:right;
    }
    div#buttonDiv{
        width:100%;
    }
    input[type="submit"]{
        font-size: 12px;
        width: 68px;
        height: 20px;
        cursor: hand;
        border:none;
        font-family:宋体;
        background-color:White;
        background-image:   url(images/but_bg.gif);
        color: white;
    }
    div#infoTable{
        overflow:auto;
        width:100%;
        height:100%;
    }
    div table{
        width:100%;
        background-color:white;
        cellpadding:1;
        cellspacing:1;
        font-size: 12px;
        text-align: center;
    }
    div table th{
        height:22;
        background-color:#7088AD;
        color: #FFFFFF;
        width:8%;
    }
    div table tr{
        height:30;
    }
    div#infoTable   table tr:nth-child(odd){
        background-color:#E6E6E6;
        color: #333333;
    }
    div#infoTable   table tr:nth-child(even){
        background-color:#fafafa;
        color: black;
    }
    div#infoTable   table tr:nth-child(1){
        background-color:#7088AD;
        color: #FFFFFF;
    }
    div#infoTable   table th:nth-last-child(1){
        width: 15%;
    }
    </style>

3. jQuery脚本代码

下面来集中看一下本页面中使用了jQuery验证器的几个HTML元素的页面代码,如下所示。

    <input type="text" id="tbxCode" name="tbxCode" maxlength="8"
    class="validate[required]" placeholder="必须输入一个不存在的订单编号"
    autofocus    required/>
    <input type="date" id="tbxDate" name="tbxDate" maxlength="10"
    class="validate[required,custom[date]]"
    placeholder="必须输入一个有效的日期"   required/>
    <input type="text"   id="tbxGoodsCode" name="tbxGoodsCode" maxlength="12"
    class="validate[required]" placeholder="必须输入商品编号"   required/>
    <input type="number" id="tbxNum" name="tbxNum" maxlength="6" value="0"
    class="validate[required,custom[integer]]"
    placeholder="必须输入一个整数值"/>
    <input type="text" id="tbxPrice" name="tbxPrice" maxlength="6" value="0"
    class="validate[required,custom[number]]"
    placeholder="必须输入一个有效的单价"/>
    <input type="email" id="tbxEmail" name="tbxEmail" maxlength="20"
    class="validate[optional,custom[email]]"
    placeholder="请输入一个有效的邮件地址"/>

最后,除了根据后台服务器端返回的变量进行页面设置的脚本代码之外,本页面中还有两个小的JavaScript函数,它们的功能是当数量文本框或单价文本框失去焦点时将金额文本框中的内容设为数量文本框中的数量值*单价文本框中的单价值。

目前该页面中的JavaScript脚本代码如代码清单2-8所示。

代码清单2-8 页面中的JavaScript脚本代码

    <link rel="stylesheet" href="Styles/validationEngine.jquery.css"
    type="text/css" media="screen"/>
    <script src="Scripts/jquery-1.5.1.min.js" type="text/javascript">
    </script>
    <script src="Scripts/jquery.validationEngine-cn.js"
    type="text/javascript"></script>
    <script src="Scripts/jquery.validationEngine.js" type="text/javascript">
    </script>
    <script>
        $(function () {
            $("#form1").validationEngine();
            $("#tbxNum").blur(function () {
                var num=parseInt($("#tbxNum").val());
                var price=parseFloat($("#tbxPrice").val());
                if (isNaN(num*price)
                    $("#tbxMoney").val("0");
                else
                    $("#tbxMoney").val(Math.round(num*price * 100, 0) / 100);
            });
            $("#tbxPrice").blur(function () {
                var num=parseInt($("#tbxNum").val());
                var price=parseFloat($("#tbxPrice").val());
                if (isNaN(num*price))
                    $("#tbxMoney").val("0");
                else
                    $("#tbxMoney").val(Math.round(num*price * 100, 0) / 100);
            });
    });

4. ASP.NET服务器端代码

最后来看一下这个页面的服务器端的ASP.NET代码部分。

在该页面中,使用了HTML 5中新增的date元素、number元素和email元素,代码如下所示。

    <input type="date" id="tbxDate" name="tbxDate" maxlength="10"
    class="validate[required,custom[date]]"
    placeholder="必须输入一个有效的日期"   required/>
    <input type="number" id="tbxNum" name="tbxNum" maxlength="6" value="0"
    class="validate[required,custom[integer]]"
    placeholder="必须输入一个整数值"/>
    <input type="email" id="tbxEmail" name="tbxEmail" maxlength="20"
    class="validate[optional,custom[email]]"
    placeholder="请输入一个有效的邮件地址"/>

对于这些元素,在目前最新版本的ASP.NET服务器端控件中,没有与之相对应的服务器端控件,所以在HTML页面代码中,不能书写成 “<asp:TextBox>”这种采用服务器端控件的形式。那么,为了在服务器端获取这几个元素的输入值,能不能使用如下所示的将runat的属性值设为server的方法呢?

    <input type="date" id="tbxDate" name="tbxDate" maxlength="10"
    class="validate[required,custom[date]]"
    placeholder="必须输入一个有效的日期"   required runat="server"/>
    <input type="number" id="tbxNum" name="tbxNum" maxlength="6" value="0"
    class="validate[required,custom[integer]]" placeholder="必须输入一个整数值"
    runat="server"/>
    <input type="email" id="tbxEmail" name="tbxEmail" maxlength="20"
    class="validate[optional,custom[email]]"
    placeholder="请输入一个有效的邮件地址" runat="server"/>

在页面中将这几个元素的runat属性值设为server,然后在浏览器中运行该页面,浏览器显示一个报错页面,如图2-10所示。

图2-10 将HTML 5中新增元素的runat属性值设为server后浏览器报错

出现这个服务器端返回的分析器错误的原因是,将这几个HTML 5中新增元素的runat属性值设为server后,ASP.NET服务器会将这几个元素视为服务器端控件,而在目前最新版本的ASP.NET中,是没有这几个服务器端控件的。

那么,应该怎样在服务器端获取用户通过这几个元素输入的值呢?

首先,将这几个新增元素的runat属性值取消,即将这几个元素作为客户端元素来处理,代码如下所示。

    <input type="date" id="tbxDate" name="tbxDate" maxlength="10"
    class="validate[required,custom[date]]"
    placeholder="必须输入一个有效的日期"   required />

然后,在服务器端代码中(本例中使用C#语言)加入Request.Form["tbxDate:].ToString()方法。例如,在服务器端的代码中,加上如下这段代码。

    protected void Page_Load(object sender,EventArgs e)
    {
        If(Page.IsPostBack)
        {
          Response.Write(Request.Form["tbxDate:].ToString());
        }
    }

在页面上表单的各元素中输入有效数据,在“订单日期”文本框中输入“2009-06-01”,如图2-11所示。

图2-11 在“订单日期”文本框中输入“2009-06-01”

然后单击新增按钮,提交表单后浏览器的显示效果如图2-12所示。

图2-12 提交表单后的页面显示效果

在这个服务器端返回的结果页面上可以看到,ASP.NET服务器端获取到了用户在date元素中输入的“2009-06-01”,并将其显示在返回的页面上。

在这个基础上,我们可以采用如下所示的代码,将获取到的用户通过HTML 5新增元素输入的内容保存到数据库中。

    string SqlStr;
    SqlStr = "insert into orders ";
    SqlStr += "values('";
    SqlStr +=Request.Form["tbxCode"].ToString().Trim().Replace("'","''")
    + "',";
    //SqlStr语句中添加date元素的输入值
    SqlStr += "'" + Request.Form["tbxDate"].ToString() + "',";
    SqlStr += "'"
    + Request.Form["tbxGoodsCode"].ToString().Trim().Replace("'", "''")+ "',";
    SqlStr += "'"
    + Request.Form["tbxBrandName"].ToString().Trim().Replace("'", "''")+ "',";
    //SqlStr语句中添加number元素的输入值
    SqlStr += Request.Form["tbxNum"].ToString() + ",";
    SqlStr += Request.Form["tbxPrice"].ToString() + ",";
    SqlStr += "'"
    + Request.Form["tbxPersonName"].ToString().Trim().Replace("'", "''")
    + "',";
    //SqlStr语句中添加email元素的输入值
    SqlStr += "'"
    + Request.Form["tbxEmail"].ToString().Trim().Replace("'", "''") + "')";
    //执行SQL语句,向数据库中追加数据
    SuccessFlag = this.ExecSingleSql(SqlStr);

此外还有一点需要补充,因为页面中各文本框控件均直接使用了客户端元素(input元素),所以不能使用ASP.NET中的ViewState机制来保存提交前各元素中的输入内容,需要在服务器端使用如下所示的代码,利用服务器端变量来统一获取各元素中的输入内容。

    public partial class Default : System.Web.UI.Page
    {
          public string Code;
          public string date;
          public string GoodsCode;
          public string brandName;
          public string num="0";
          public string price="0";
          public string money="0";
          public string PersonName;
          public string Email;
          protected void Page_Load(object sender, EventArgs e)
          {
              if (Page.IsPostBack)
              {
                  this.Code = Request.Form["tbxCode"].ToString();
                  this.date = Request.Form["tbxDate"].ToString();
                  this.GoodsCode = Request.Form["tbxGoodsCode"].ToString();
                  this.brandName = Request.Form["tbxBrandName"].ToString();
                  this.num = Request.Form["tbxNum"].ToString();
                  this.price = Request.Form["tbxPrice"].ToString();
                  double temp = double.Parse(this.num)* double.Parse(this.price);
                  this.money = Math.Round(temp, 2).ToString();
                  this.PersonName = Request.Form["tbxPersonName"].ToString();
                  this.Email = Request.Form["tbxEmail"].ToString();
              }
        }

然后在JavaScript脚本代码中,在装载页面时将表单中的各元素内容设为提交前保存在服务器端变量中的各项内容,代码如下所示。

    $(function () {
        $("#tbxCode").val("<%=Code%>");
        $("#tbxDate").val("<%=date%>");
        $("#tbxGoodsCode").val("<%=GoodsCode%>");
        $("#tbxBrandName").val("<%=brandName%>");
        $("#tbxNum").val("<%=num%>");
        $("#tbxPrice").val("<%=price%>");
        $("#tbxMoney").val("<%=money%>");
        $("#tbxPersonName").val("<%=PersonName%>");
        $("#tbxEmail").val("<%=Email%>");
    });

接下来,在查看完整的ASP.NET服务器端脚本代码之前,先查看一下在该页面中单击各个按钮以及对一览表执行某个动作后服务器端所应执行的处理,如表2-2所示。

表2-2 该页面中各个按钮及其功能

再来看一下为了在这个应用程序中使用SQLServer Express数据库,而在web.config配置文件中添加的连接字符串。读者需要根据自己的数据库类型(可以使用MySql和Oracle等其他数据库)及其存放位置做相应的修改。

    <configuration>
        <connectionStrings>
            <add name="dbConnection"
            connectionString="Data Source=lln\sqlexpress;
            Initial Catalog=HTML5TEST;Integrated Security=True"
            providerName="System.Data.SqlClient" />
        </connectionStrings>

下面来看一下该页面完整的ASP.NET服务器端脚本代码,如代码清单2-9所示。

代码清单2-9 页面中完整的ASP.NET服务器端脚本代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Configuration;
    using System.Data;
    using System.Data.SqlClient;
    namespace HTML5TEST
    {
        public partial class Default : System.Web.UI.Page
        {
            private System.Data.SqlClient.SqlConnection SqlCon;
            private System.Data.SqlClient.SqlDataAdapter DataAdapter;
            private System.Data.SqlClient.SqlCommand Command;
            private int myErrorNumber = 0;     //数据库返回的错误号
            private string myErrorMessage = "";//数据库返回的错误信息
            string Constr;                     //连接字符串
            //用于保存表单中各输入控件内容的变量
            public string Code;
            public string date;
            public string GoodsCode;
            public string brandName;
            public string num="0";
            public string price="0";
            public string money="0";
            public string PersonName;
            public string Email;
            //设置订单编号文本框是否为只读状态
            //修改与删除状态时为只读状态,否则为可读写状态
            public bool codeRead=false;
            private bool SuccessFlag;         //数据库操作是否成功
            //装载页面
            protected void Page_Load(object sender, EventArgs e)
            {
                //从web.config文件中读取连接字符串
                Constr = System.Configuration.ConfigurationManager.
                ConnectionStrings["dbConnection"].ToString();
                //设置SQL Server数据库连接对象
                this.SqlCon = new System.Data.SqlClient.SqlConnection();
                this.SqlCon.ConnectionString = Constr;
                //连接数据库
                SuccessFlag = OpenDBConnection();
                if (SuccessFlag == false)
                {
                    this.ShowError("数据库连接失败。");
                }
                else
                {
                    //从数据库中读取所有订单数据,装入一览表
                    this.datatable.DataSource = CreateDataSource();
                    this.datatable.DataBind();
                }
                if (Page.IsPostBack)
                {
                    //用变量来保存用户在各表单元素中的输入内容
                    this.Code = Request.Form["tbxCode"].ToString();
                    this.date = Request.Form["tbxDate"].ToString();
                    this.GoodsCode = Request.Form["tbxGoodsCode"].ToString();
                    this.brandName = Request.Form["tbxBrandName"].ToString();
                    this.num = Request.Form["tbxNum"].ToString();
                    this.price = Request.Form["tbxPrice"].ToString();
                    //设置金额文本框中内容=数量*单价
                    double temp;
                    temp=double.Parse(this.num)*double.Parse(this.price);
                    this.money = Math.Round(temp, 2).ToString();
                    this.PersonName = Request.Form["tbxPersonName"].ToString();
                    this.Email = Request.Form["tbxEmail"].ToString();
                }
            }
            //单击新增按钮
            protected void btnNew_Click(object sender, EventArgs e)
            {
                this.Code=string.Empty;
                this.dataInit();//清空表单元素中的内容
                //将一览表中当前选取数据变为非选取状态
                this.datatable.SelectedIndex = -1;
                this.btnUpdate.Enabled = false;//修改按钮变为禁止单击状态
                this.btnDelete.Enabled = false;//删除按钮变为禁止单击状态
                this.btnClear.Enabled = false; //清除按钮变为禁止单击状态
                this.btnAdd.Enabled = true;    //追加按钮变为允许单击状态
            }
            //单击追加按钮
            protected void btnAdd_Click(object sender, EventArgs e)
            {
                DataSet ds;
                string SqlStr;
                //查看输入的订单编号是否已存在
                SqlStr = "select count(*) count from orders where code='"
                + strFormat(Request.Form["tbxCode"].ToString())+ "'";
                ds = this.GetDataFromDB(SqlStr);
                if (ds == null)
                {
                    this.ShowError("数据添加失败。");
                    return;
                }
                //订单编号已存在
                if (Int32.Parse(ds.Tables[0].Rows[0]["count"].ToString()) > 0)
                {
                    this.ShowError("输入的订单编号在数据库中已存在。");
                    return;
                }
                //追加数据
                SqlStr = "insert into orders ";
                SqlStr += "values('"
                + strFormat(Request.Form["tbxCode"].ToString())+ "',";
                SqlStr += "'" +Request.Form["tbxDate"].ToString() + "',";
                SqlStr += "'"
                + strFormat(Request.Form["tbxGoodsCode"].ToString())+ "',";
                SqlStr += "'"
                + strFormat(Request.Form["tbxBrandName"].ToString())+ "',";
                SqlStr += Request.Form["tbxNum"].ToString() + ",";
                SqlStr += Request.Form["tbxPrice"].ToString() + ",";
                SqlStr += "'"
                + strFormat(Request.Form["tbxPersonName"].ToString())+ "',";
                SqlStr += "'"
                + strFormat(Request.Form["tbxEmail"].ToString())+ "')";
                SuccessFlag = this.ExecSingleSql(SqlStr);
                if (SuccessFlag == false)//添加数据失败
                {
                    this.ShowError("数据添加失败。");
                }
                else//添加数据成功
                {
                    this.codeRead = true;         //订单编号文本框变为只读状态
                    this.btnUpdate.Enabled = true;//修改按钮变为允许单击状态
                    this.btnDelete.Enabled = true;//删除按钮变为允许单击状态
                    this.btnClear.Enabled = true; //清除按钮变为允许单击状态
                    this.btnAdd.Enabled = false;  //追加按钮变为禁止单击状态
              //刷新一览表,显示被追加的数据
                    this.datatable.DataSource = CreateDataSource();
                    this.datatable.DataBind();
                }
            }
            //单击修改按钮
            protected void btnUpdate_Click(object sender, EventArgs e)
            {
                string SqlStr;
                //在数据库中修改数据
                SqlStr = "update orders ";
                SqlStr += "set orderDate='"
                +Request.Form["tbxDate"].ToString()+ "',";
                SqlStr += "goodsCode='"
                + strFormat(Request.Form["tbxGoodsCode"].ToString()) + "',";
                SqlStr += "brandName='"
                + strFormat(Request.Form["tbxBrandName"].ToString()) + "',";
                SqlStr += "num=" + Request.Form["tbxNum"].ToString() + ",";
                SqlStr += "price=" + Request.Form["tbxPrice"].ToString() + ",";
                SqlStr += "personName='"
                + strFormat(Request.Form["tbxPersonName"].ToString()) + "',";
                SqlStr += "email='"
                + strFormat(Request.Form["tbxEmail"].ToString()) + "' ";
                SqlStr += "where code='"
                + strFormat(Request.Form["tbxCode"].ToString()) + "'";
                SuccessFlag = this.ExecSingleSql(SqlStr);
                if (SuccessFlag == false)//数据修改失败
                {
                    this.ShowError("数据修改失败。");
                }
                else//数据修改成功
                {
                    this.codeRead = true;//订单编号文本框保持只读状态
                    //刷新一览表,显示修改后数据
                    this.datatable.DataSource = CreateDataSource();
                    this.datatable.DataBind();
                }
            }
            //单击删除按钮
            protected void btnDelete_Click(object sender, EventArgs e)
            {
              //从数据库中删除数据
                string SqlStr;
                SqlStr = "delete from orders ";
                SqlStr += "where code='"
                + strFormat(Request.Form["tbxCode"].ToString()) + "'";
                SuccessFlag = this.ExecSingleSql(SqlStr);
                if (SuccessFlag == false)//删除数据失败
                {
                    this.ShowError("数据删除失败。");
                }
                else//删除数据成功
                {
                    //刷新一览表
                    this.datatable.DataSource = CreateDataSource();
                    this.datatable.DataBind();
                    this.codeRead = false;         //订单编号文本框变为可读写状态
                    //将一览表中当前选取数据变为非选取状态
                    this.datatable.SelectedIndex = -1;
                    this.Code = string.Empty;       //清除订单编号文本框中的内容
                    dataInit();//清除表单中其他各输入元素中的内容
                    this.btnUpdate.Enabled = false; //修改按钮变为禁止单击状态
                    this.btnDelete.Enabled = false; //删除按钮变为禁止单击状态
                    this.btnClear.Enabled = false;  //清除按钮变为禁止单击状态
                    this.btnAdd.Enabled = true;     //追加按钮变为允许单击状态
                }
            }
            //单击清除按钮
            protected void btnClear_Click(object sender, EventArgs e)
            {
                //订单编号文本框保持只读状态
                this.codeRead = true;
                //清除页面中除了订单编号文本框之外的其他所有文本框中的内容
                this.dataInit();
            }
            //单击一览表中某条数据的编辑按钮
            protected void datatable_ItemCommand(object source,
            DataGridCommandEventArgs e)
            {
                if (e.CommandName == "select")
                {
                    //表单中各文本框中的内容被设定为选取数据的各项对应内容
                    this.Code = e.Item.Cells[0].Text;
                    this.date = e.Item.Cells[1].Text;
                    this.GoodsCode = e.Item.Cells[2].Text;
                    if (e.Item.Cells[3].Text == "&nbsp;")
                        this.brandName = "";
                    else
                        this.brandName = e.Item.Cells[3].Text;
                    this.num = e.Item.Cells[4].Text;
                    this.price = e.Item.Cells[5].Text;
                    //设置金额文本框中内容=数量*单价
                    double num= double.Parse(this.num);
                    double price= double.Parse(this.price);
                    double temp= num * price;
                    this.money = Math.Round(temp, 2).ToString();
                    if (e.Item.Cells[7].Text == "&nbsp;")
                        this.PersonName = "";
                    else
                        this.PersonName = e.Item.Cells[7].Text;
                    if (e.Item.Cells[8].Text == "&nbsp;")
                        this.Email = "";
                    else
                        this.Email = e.Item.Cells[8].Text;
                    this.codeRead = true;         //订单编号文本框变为只读状态
                    this.btnUpdate.Enabled = true;//修改按钮变为允许单击状态
                    this.btnDelete.Enabled = true;//删除按钮变为允许单击状态
                    this.btnClear.Enabled = true; //清除按钮变为允许单击状态
                    this.btnAdd.Enabled = false;  //追加按钮变为允许单击状态
                }
            }
            //单击一览表右下角的页号进行翻页
            protected void datatable_PageIndexChanged(object source,DataGridPageChangedEventArgs e)
            {
                this.datatable.CurrentPageIndex = e.NewPageIndex;
                this.datatable.DataSource = CreateDataSource();
                this.datatable.DataBind();
            }
            //清空一览表中除订单编号文本框之外其他所有文本框中的内容
            private void dataInit()
            {
                this.date = string.Empty;
                this.GoodsCode = string.Empty;
                this.brandName = string.Empty;
                this.num = "0";
                this.price = "0";
                this.money = "0";
                this.PersonName = string.Empty;
                this.Email = string.Empty;
            }
            //连接数据库
            private bool OpenDBConnection()
            {
                try
                {
                    this.SqlCon.Open();
                    return true;
                }
                catch (SqlException e)
                {
                    this.myErrorNumber = e.Number;
                    this.myErrorMessage = e.Message;
                    return false;
                }
                catch (Exception e)
                {
                    this.myErrorNumber = e.GetHashCode();
                    this.myErrorMessage = e.Message;
                    return false;
                }
            }
            //在页面中显示错误信息
            private void ShowError(string myErrorMessage)
            {
                string strErrMsg;
                if(!this.myErrorMessage.Equals(""))
                    strErrMsg = this.myErrorNumber + ":" + this.myErrorMessage;
                else
                    strErrMsg = myErrorMessage;
                Page.ClientScript.RegisterStartupScript(Page.GetType(), "",
                "<script language='JavaScript'>alert('" + strErrMsg
                + "');</script>");
            }
            //获取所有订单数据
            private DataView CreateDataSource()
            {
                DataSet ds;
                DataView dv;
                DataTable dt = new DataTable();
                DataRow dr;
                string SqlStr;
                double temp;
                dt.Columns.Add(new DataColumn("code"));
                dt.Columns.Add(new DataColumn("orderDate"));
                dt.Columns.Add(new DataColumn("goodsCode"));
                dt.Columns.Add(new DataColumn("brandName"));
                dt.Columns.Add(new DataColumn("num"));
                dt.Columns.Add(new DataColumn("price"));
                dt.Columns.Add(new DataColumn("money"));
                dt.Columns.Add(new DataColumn("personName"));
                dt.Columns.Add(new DataColumn("email"));
                SqlStr = "select * from orders order by code";
                ds = this.GetDataFromDB(SqlStr);
                if (ds == null)
                {
                    dv = null;
                    dt = null;
                    return dv;
                }
                String orderDate;
                for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
                {
                    dr = dt.NewRow();
                    dr[0] = ds.Tables[0].Rows[i]["code"].ToString();
                    orderDate=ds.Tables[0].Rows[i]["orderDate"].ToString();
                    dr[1] = DateTime.Parse(orderDate).ToString("yyyy-MM-dd");
                    dr[2] = ds.Tables[0].Rows[i]["goodsCode"].ToString();
                    dr[3] = ds.Tables[0].Rows[i]["brandName"].ToString();
                    dr[4] = ds.Tables[0].Rows[i]["num"].ToString();
                    dr[5] = ds.Tables[0].Rows[i]["price"].ToString();
                    temp = double.Parse(ds.Tables[0].Rows[i]["num"].ToString())
                    * double.Parse(ds.Tables[0].Rows[i]["price"].ToString());
                    dr[6] = Math.Round(temp, 2).ToString();
                    dr[7] = ds.Tables[0].Rows[i]["personName"].ToString();
                    dr[8] = ds.Tables[0].Rows[i]["email"].ToString();
                    dt.Rows.Add(dr);
                }
                dv = new DataView(dt);
                return dv;
            }
            //根据SQL语句从数据库中获取数据
            private System.Data.DataSet GetDataFromDB(string SqlStr)
            {
                DataSet ds;
                try
                {
                    ds = new DataSet();
                    this.DataAdapter = new SqlDataAdapter(SqlStr,
                    this.SqlCon);
                    this.DataAdapter.Fill(ds);
                    return ds;
                }
                catch (SqlException e)
                {
                    this.myErrorNumber = e.Number;
                    this.myErrorMessage = e.Message;
                    return null;
                }
                catch (Exception e)
                {
                    this.myErrorNumber = e.GetHashCode();
                    this.myErrorMessage = e.Message;
                    return null;
                }
            }
            //根据SQL语句执行增删改操作
            private bool ExecSingleSql(string SqlStr)
            {
                try
                {
                    this.Command = new SqlCommand(SqlStr);
                    this.Command.Connection = this.SqlCon;
                    this.Command.ExecuteNonQuery();
                    return true;
                }
                catch (SqlException e)
                {
                    this.myErrorNumber = e.Number;
                    this.myErrorMessage = e.Message;
                    return false;
                }
                catch (Exception e)
                {
                    this.myErrorNumber = e.GetHashCode();
                    this.myErrorMessage = e.Message;
                    return false;
                }
            }
            Private String strFormat(String str)
            {
                return str.Trim().Replace("'","''");
            }
        }
    }

最后,由于在服务器端使用了一个codeRead变量来控制订单编号文本框的只读状态,当表单处于修改或删除数据状态时该变量为True,订单编号文本框为只读状态,当表单处于新增数据状态时该变量为False,该文本框为可读写状态,所以在JavaScript脚本中,添加装载页面时的代码,根据该变量来设置订单编号文本框的只读状态,代码如下所示。

    <%if(codeRead)
    {%>
        $("#tbxCode").attr("ReadOnly","ReadOnly");
    <% }
    else
    {
    %>
        $("#tbxCode").removeAttr('ReadOnly');
    <% }%>

现在该页面的完整JavaScript脚本代码如代码清单2-10所示。

代码清单2-10 页面的完整JavaScript脚本代码

    <link rel="stylesheet" href="Styles/validationEngine.jquery.css"
    type="text/css" media="screen"/>
    <script src="Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.validationEngine-cn.js"
    type="text/javascript"></script>
    <script src="Scripts/jquery.validationEngine.js"
    type="text/javascript"></script>
    <script>
        $(function () {
            $("#form1").validationEngine();
            $("#tbxCode").val("<%=Code%>");
            $("#tbxDate").val("<%=date%>");
            $("#tbxGoodsCode").val("<%=GoodsCode%>");
            $("#tbxBrandName").val("<%=brandName%>");
            $("#tbxNum").val("<%=num%>");
            $("#tbxPrice").val("<%=price%>");
            $("#tbxMoney").val("<%=money%>");
            $("#tbxPersonName").val("<%=PersonName%>");
            $("#tbxEmail").val("<%=Email%>");
            <%if(codeRead)
            {%>
        $("#tbxCode").attr("ReadOnly","ReadOnly");
            <% }
            else
            {
            %>
        $("#tbxCode").removeAttr('ReadOnly');
            <% }%>
            $("#tbxNum").blur(function () {
        var num= parseInt($("#tbxNum").val());
        var price= parseFloat($("#tbxPrice").val());
        if (isNaN(num*price))
            $("#tbxMoney").val("0");
        else
            $("#tbxMoney").val(Math.round(num * price * 100, 0) / 100);
            });
            $("#tbxPrice").blur(function () {
        var num= parseInt($("#tbxNum").val());
        var price= parseFloat($("#tbxPrice").val());
        if (isNaN(num*price))
            $("#tbxMoney").val("0");
        else
            $("#tbxMoney").val(Math.round(num * price * 100, 0) / 100);
            });
            $("#btnNew").click(function () {
        $('input[id^="tbx"]').removeClass();
            })
            $("#btnDelete").click(function () {
        $('input[id^="tbx"]').removeClass();
            });
        });
    </script>

2.3 本章小结

本章首先通过一个利用HTML 5中的结构元素制作Web应用程序中的菜单的案例来阐述如何使用这些结构元素制作一个语义清晰、结构分明的菜单页面。接下来,通过一个综合使用HTML 5中的结构元素和表单元素、jQuery验证器与ASP.NET制作HTML 5版本的Web应用程序的案例来阐述如何使用HTML 5中的结构元素搭建Web应用程序的框架结构,如何对用户在HTML 5新增的表单元素中输入的内容进行验证,以及如何让服务器端能够正确获取到这些用户在新增表单元素中输入的内容并将其保存在数据库中。

下一章将通过一些案例来阐述如何使用HTML 5新增的canvas元素与Canvas API在页面上绘制图形、图像及动画,以及如何利用Canvas API制作Web页面上的小游戏。