ASP.NET 2.0程序开发详解 ---------15.2 AJAX的核心技术

---------http://book.csdn.net/bookfiles/376/10037614186.shtml 

15.2  AJAX的核心技术

在上面一节中,已经提到了AJAX是一种技术的组合。AJAX是由几种技术组合而   成的。

(1)       XmlHttpRequest—XmlHttpRequest对象允许浏览器通过它与Web服务器进行通信。这个对象为页面提供了客户端和服务器端的异步通信功能。在Internet Explorer中,这个功能由“MSXML”ActiveX组件提供;在FireFox中,这个功能由一个叫XmlHttpReqeust的对象来提供。在编写AJAX代码时,需要判断浏览器类型,并为不同浏览器提供不同的XmlHttpRequest的调用代码。

(2)JavaScript—所有的浏览器都支持JavaScript脚本语言。AJAX使用JavaScript脚本语言来操作XmlHttpRequest对象、操作DOM和CSS等。

(3)DHTML/DOM—能正确显示AJAX应用程序页面的浏览器必须要能通过DOM动态更新HTML元素的内容。

(4)使用XML传输数据—虽然也能使用HTML或者其他的格式在客户端和服务器之间传递数据,不过XML显然是标准的做法,并且使用XML容易结构化和层次化数据。

下面就对这几种技术进行简要的介绍。

15.2.1  JavaScript 简介

毫无疑问,JavaScript在AJAX中扮演了指挥的角色。JavaScript负责将各个不同的技术粘合在一起协同工作,组织漂亮的页面。AJAX应用程序在执行时,会预先将客户端所有的代码下载到内存中,下载的内容包括数据、HTML代码和逻辑控制代码。JavaScript就是实现逻辑控制的工具。

JavaScript是一种通用的脚本语言,它与C系列的语言有非常多的相似点。JavaScript语言的特点用一句话概括就是“它是一种通用的,弱类型的,解释型的脚本语言”。

弱类型表明JavaScript的变量可以不显式申明为某种数据类型,例如string类型、int类型等等。同一个变量可以被赋予不同类型的数据。下面的代码是合法的:

var  i = 1;

i = 100.05;

i='3.1415926';

变量i首先被赋予了一个整形的值,然后赋予了一个浮点数,最后把一个字符串赋予了它。只有弱类型的语言可以这样做,可以与C#语言进行对比。

解释型脚本语言意味着JavaScript不会被编译为可执行的机器码,解释器直接按照源代码所表述的翻译执行。部署JavaScript时,将JavaScript的代码文件放置在Web服务器上,客户端发出请求时,把JavaScript文件直接通过网络传递给客户端,然后客户端的浏览器对下载的JavaScript代码进行解释并执行预定的操作。还可以在代码中动态地使用表达式,然后调用JavaScript的Eval方法对表达式进行解析,并得到表达式的结果。这种方式会降低程序的运行速度,不过它带来了非常好的灵活性,应该恰当地使用它。

JavaScript是一种通用的语言,它可以用在大多数的编程任务中。例如,JavaScript可以用来编写运行在Windows下的程序,还可以用来编写游戏的脚本,等等。JavaScript语言和大多数通用语言一样,支持多种数据类型—整形数、浮点数、字符串、日期、数组等,它也支持用于文本处理的正则表达式,支持数学的各种函数。使用JavaScript也可以定义结构和类。

在浏览器中,一些浏览器内置的功能,如CSS、DOM和XMLHttpRequest对象暴露给了JavaScript的解释器,因此页面的开发人员可以直接在JavaScript代码中调用这些功能来控制页面。

这里不是详细讲解JavaScript的地方,如果希望了解更多的信息可以查阅相关的书籍。

15.2.2  文档对象模型(DOM)

文档对象模型(DOM),为访问HTML文档中所有的元素提供了方法。在HTML文档中,包括可见的元素,如超级链接、文本输入框(input)、按钮等,不可见的元素,如HTML文档的头部信息、DIV区域、SPAN区域等,都可以在DOM中以类似的方式访问。与DOM访问有关的对象有两个:

l  浏览器对象模型

l  文档对象模型

1.浏览器对象模型

浏览器对象模型代表了浏览器自身。一般来说,浏览器对象模型包括了一个根节      点—Window对象。Window对象包含了几个其他对象的引用,包括navigator、history、location、Frames和document(文档)对象。document对象包括了页面的元素,它就是一个DOM对象的实例引用。图15-3所示是浏览器对象模型的结构。

图15-3  浏览器对象模型

在使用中常常分不大清楚浏览器对象模型和文档对象模型,要记住它们的区别在于,浏览器对象模型访问的是浏览器自身的信息和功能,通过操作window对象,可以访问多种不同的浏览器的功能。因为Window是根元素,所以它常常被隐式地使用。下面的两个JavaScript语句是等同的:

alert("隐式的访问window对象");

等同于

window.alert("显式的访问window对象");

window对象是默认首先访问的对象。因此,从window对象访问document对象也可以用相同的方式进行,例如访问document对象的write方法:

window.document.write("显式window对象");

document.write("隐式window对象");

由于web应用程序的开发会大量地访问浏览器对象模型,如history记录、页面中的框架信息等,Web开发人员很有必要了解更多的浏览器对象模型的细节。不过本书在这里不做更多的介绍,读者可以查阅MSDN以获取更多的帮组信息。

2.文档对象模型(DOM)

伴随着浏览器的发展DOM逐渐完善。早期的DOM,存在于Netscape 2/3和Internet Explorer 3。它们的创建是为了达到相似的目的,不过实现上却彼此有很大的不同;另外,它们都提供了一些方法来访问HTML文档的元素,但是不能访问所有的HTML元素。这给使用者带来了很多的不便,也使早期的开发人员不能使用这样的DOM给用户创建更动态的页面。

Netscape 4.0和Internet Explorer 4在DHTML基础上工作,开发人员可以通过DOM访问更多的HTML元素以及它们的属性,能够通过DOM创建真正的动态页面。不过由于浏览器提供商的不同,使Netscape和IE浏览器在DOM的实现上有各种各样的差别,给开发人员带来了许多痛苦。

Internet Exploer 5/5.5/6/7.0,Netscape 6+以及随后的Mozilla/Firefox浏览器开始按照W3C的推荐标准建造它们的对象模型,不过不能指望在短时间内,所有浏览器会为JavaScript开发人员提供完全一致的访问接口。

按照DOM的发展过程,W3C组织将DOM分为了4个版本。前3个版本(DOM 0、1、2)已经被各种不同的浏览器所实现;版本3刚成为W3C的建议标准,还没有浏览器实现它。下面介绍DOM的4个版本。

(1)DOM版本0。这个版本的DOM不是W3C所定义的,它和早期的浏览器中(Netsacape 2/3、Internet Explorer)中提供的DOM非常近似。这个版本的DOM更象是一系列功能的定义,提供了有限的HTML文档元素的访问。

(2)DOM版本1。这个版本的DOM定义了如何通过一系列公共的方法和属性来操作所有的文档元素。在这个版本中,DOM暴露所有的文档元素用以读写操作。DOM 1包含了两个元素—DOM Core和DOM HTML。

① DOM Core元素引用了一系列的可以代表任何结构化文档的通用接口,例如XML文档。DOM Core为其他的结构化文档提供了访问支持,如XML。

② DOM HTML元素引用了更高版本的接口以提供便捷的HTML文档的访问。DOM HTML元素在内部会引用DOM Core的接口。

主要的浏览器都能对这版本的DOM提供完善的支持。该版本在1998年成为W3C的推荐标准。

(3)DOM版本2。这个版本包括了版本0和1的所有功能,并进行了很大的扩充。它提供了操作层叠样式表元素的方法,还提供了更多的与XML相关的页面元素的访问方式。即使是宣称自己符合DOM版本2的浏览器也没有能完全支持DOM 2。DOM 2包含了6个方面的内容:DOM2 Core、DOM2 HTML、DOM2 Style/CSS、DOM2 Event、DOM2 Traversal and Range、DOM2 Views。

① DOM2 Core和DOM2 HTML是DOM版本1的DOM Core和DOM HTML的延伸。

② DOM2 Style/CSS提供了访问样式表元素的接口和方法。

③ DOM2 Event定义了一个通用的页面事件系统,它引入了事件流、事件抛出和取消等概念。

④ DOM2 Traversal and Range提供了方法允许脚本在文档的元素中自由的移动,以及识别出文档的一部分。

⑤ DOM2 Views允许脚本动态的访问和更新文档显示的内容。

⑥ DOM版本2在2000年被批准,但是到2003年1月才正式成为W3C的推荐       标准。

(4)DOM版本3。版本3代表了DOM最终的标准化方向。在这个版本中,将DOM对XML的支持扩展到1.1版本,以及其他与XML相关的特性的支持。在这个版本中,DOM符合了XML Schema 1.0和SOAP 1.2等W3C的XML推荐标准。DOM版本3增加了5个不同方面的内容:DOM3 Core、DOM3 Load and Save、DOM3 Validation、DOM3 Events和DOM3 Xpath。

① DOM3 Core是对DOM Core和DOM2 Core的进一步扩充。

② DOM3 Load and Save允许在DOM中动态的加载XML文档,同时规定了如何将DOM文档序列化为XML文档。

③ DOM3 Validation提供了动态更新文档的方法并保证文档和更新内容格式的合   法性。

④ DOM3 Events扩展了DOM2 Events中定义的事件系统,并对键盘事件的处理作了进一步的强化。

⑤ DOM3 XPath提供了以XPath语法访问DOM对象内部的HTML元素树的途径。

⑥ 这个版本的DOM还没有全部成为推荐标准。到目前为止,DOM3 Core、DOM3 Load and Save、DOM3 Validation成为了推荐标准。

可以预见的是,如果未来的浏览器符合DOM3的标准,将极大方便开发人员的工作。

接下来,看一个简单页面的DOM结构。下面是这个页面的HTML代码:

<!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>DOM 结构</title>

</head>

    <body>

        <h1>标题</h1>

        <p> 这是一段文字</p>

        <ul>

            <li> Item 1</li>

            <li>Item 2</li>

        </ul>

    </body>

</html>

这个页面对应的DOM结构如图15-4所示。

从图15-4可以非常直观地得出DOM结构是一棵N叉树,随着HTML标签的增加,树将迅速变得非常复杂。

图15-4  DOM结构示意图

15.2.3  CSS(层叠样式表)

层叠样式表(Cascading Style Sheets,简称CSS),是Web应用程序设计中非常重要的一个环节。不论是在传统的Web应用程序中还是在最近的AJAX程序中,CSS都被频繁地使用。样式表提供了一个页面视觉效果的中央控制系统。通过样式表可以精确控制每个独立的元素的外观和行为。除了每个元素单独的颜色、边框、背景、透明度和大小等属性可以在样式表中进行控制以外,样式表还可以控制一组元素的排列方式,元素在页面中的布局形式等。样式表还可以实现一些令人惊叹的视觉效果,如可以对元素应用某些滤镜效果。

在Web应用程序中,样式表可以存放在一个单独的文件中,并且不同Web页面可以使用相同的样式文件。修改一个样式表文件就可以改变所有引用该文件的页面的视觉效果。这与ASP.NET 2.0的母版页有类似之处,不过母版页着眼于页面的布局,而样式表关注的是每一类或是每一个元素的视觉效果。

样式表带给了Web应用程序非常多的好处,掌握样式表的使用是一个合格的Web页面设计人员的必修课。样式表可以为设计人员作以下的事情:

(1)将格式和结构分离。HTML定义了网页的结构和各个元素的功能,让浏览器自己决定如何显示这些HTML元素。最初的时候,HTML不包括<Font>、<I>等控制页面外观的标签;然后,HTML加入了这些标签,设计人员开始大量使用它们来控制页面外观,HTML变得异常的复杂和混乱。向一个现成的HTML文档中添加内容不再是一件轻松的事情。样式表的出现让HTML代码可以重新变得简洁。样式表定义元素的格式,HTML定义页面的结构,两者的功能分割开来,使开发人员能更加轻松地对页面的布局进行控制。

(2)更加精确地控制格式。HTML能够通过一些标签对格式进行一些控制,但是,不够精确,例如,HTML不能精确地生成80像素的高度,不可能控制行间距或者字间距,不能在页面上精确的定位图像的位置,而样式表可以。

(3)可以制作出体积更小下载更快的网页。使用样式表可以减少表格的标签及其他增加HTML体积的代码,减少为控制格式使用的空白图片的用量,由于多个页面可以共用一个样式表文件,只下载一次,则所有页面都可以使用它。

从HTML文档中加载样式表有以下4种方式。

(1)链接外部的样式表文件。

可以通过HTML的Link元素来指定外部的样式表,下面是几个使用Link元素加载样式表文件的实例:

<LINK REL=StyleSheet HREF="mystyle.css" TYPE="text/css" MEDIA=screen>

<LINK REL=StyleSheet HREF="mystyle.css" TYPE="text/css" MEDIA="screen,print">

<LINK REL=StyleSheet HREF="color.css" TYPE="text/css" TITLE="MyColorCSS" MEDIA="screen">

在LINK标签中,使用REL指定链接的文档与HTML文档之间的关系,这里指定链接的文档为样式表。使用TYPE属性指定链接文档的内容类型,“text/css”代表了层叠样式表文件;TITLE属性为引入的样式表指定一个名称。可以将多个外部样式表指定为同样的名称,这样它们就共同组成这个命名样式表,例如:

<LINK REL=StyleSheet HREF="1.css" TITLE="CSSTITLE">

<LINK REL=StyleSheet HREF="2.css" TITLE="CSSTITLE">

<LINK REL=StyleSheet HREF="3.css" TITLE="CSSTITLE">

上面的例子中,引入3个外部样式表文件,在HTML文档中被纳入名称为CSSTTITLE的样式表中。

(2)内嵌的样式表。

可以使用STYLE元素在文档中嵌入样式表:

<HTML>

    <HEAD>

            <STYLE TYPE="text/css" MEDIA="screen">

                <!--

                    BODY {background:url(foo.gif) red;color:black}

                    P EM {background:yellow; color:black}

                    .note {margin-left:5em;margin-right: 5em}

                -->

            </STYLE>

    </HEAD>

    <BODY>

    </BODY>

</HTML>

在STYLE标签中,同样可以指定TYPE属性和MEDIA属性。为了避免不支持样式表的浏览器将样式表代码显示给用户,需要把样式表代码放置在<!-- -->这个注解标签之内。

(3)输入样式表。

在STYLE标签中,除了直接将样式表代码列出之外,还可以使用@import指令输入一个外部的样式表文件,例如:

<STYLE TYPE="text/css" MEDIA="screen">

<!--

    @import url(http://localhost/1.css);

    @import url(/css/mysitestyle.css);

    TD {background:green; color:lightblue}

-->

</STYLE>

(4)内联样式。

样式可以使用STYLE属性,在BODY(包括BODY)标签之内的标签声明中使用内联。样式表的代码放在style属性后面的文本中,样式表条目之间用分号分割,样式表条路数量不限,如下所示:

   <table border="0" cellpadding="0" cellspacing="0" style="width: 100%; height: 50%">

            <tr>

                <td colspan="2" style="height: 200px">

                </td>

            </tr>

            <tr>

                <td style="width: 200px">

                </td>

                <td>

                </td>

            </tr>

    </table>

上面就是4种使用样式表的方法。样式表的使用足够用一本书来详细解说,这里就不再花更多的笔墨来说明了,读者如果对样式表不是很了解,可以查阅相关的书籍和文档。

15.2.4  XMLHttpRequest对象

没有XMLHttpRequest对象就没有AJAX。这句话反映了XMLHttpRequest对象在AJAX应用程序中的重要性。为什么这样说呢?AJAX的核心思想是浏览器与Web服务器的异步通信,而与异步通信有关的操作全部通过XMLHttpRequest对象来完成。

XMLHttpRequest对象所使用的技术自1998年就开始使用了。微软大概是第一个使用这个技术的公司。微软在它的Outlook Web Access这个产品中首次使用了这个技术。通过使用相关的ActiveX组件,Internet Explorer 4.0浏览器中已经可以使用XMLHttpRequest对象了。

近两年,Google成功地将XMLHttpRequest技术用于它的产品中,如GoogleMap和GMail,因此在Web业界掀起了使用XMLHttpRequest技术的浪潮,随之而来的才是AJAX这个新的名称。

1.XMLHttpRequest对象的创建

其他的浏览器提供商在Internet Explorer支持XMLHttpRequest对象不久以后,意识到XMLHttpRequest的重要性,也各自在自己的产品中加入了对XMLHttpRequest的支持。到目前为止,所有的主流浏览器都支持XMLHttpRequest对象。兼容性的问题再次出现,非Internet Explorer核心的浏览器并不支持ActiveX组件的使用,它们将XMLHttpRequest对象内置在浏览器的内部,因此创建的方式有所不同。这个问题很容易解决,下面的代码演示了如何判断浏览器的种类并创建一个XMLHttpRequest对象:

var xmlHttpObj;

if (window.ActiveXObject)

{

try

{

    xmlHttpObj = new ActiveXObject("Microsoft.XMLHTTP");

}

catch (e)

{

    xmlHttpObj = new ActiveXObject("Msxml2.XMLHTTP");

}

}

    else

xmlHttpObj = new XMLHttpRequest();

上面的代码中,window.ActiveXObject属性用来判断浏览器是否支持创建ActiveX组件对象,如果值为True,那么说明这个浏览器是Internet Explorer系列的浏览器,反之则不是。对于Internet Explorer系列的浏览器,使用new ActiveXObject(“Microsoft.XMLHttp”)来创建一个XMLHttpRequest的对象,否则使用new XMLHttpRequest()创建对象。由于Internet Explorer所在系统中,安装的XML Parser版本不同,new ActiveXObject()方法中指定的XMLHttpRequest对象的名称也略有区别。幸运的是,不论安装的是什么版本的XML Parser,都会包含“Microsoft.XMLHttp”或“Msxml2.XMLHTTP”。

毫无疑问,上面这段代码将在AJAX模式的应用程序中无数次使用。于是,把上面这段代码放在一个方法内:

function GetXmlHttpRequest()

{

var xmlHttp=null;

if (window.ActiveXObject)

{

try

{

    xmlHttpObj = new ActiveXObject("Microsoft.XMLHTTP");

}

catch (e)

{

    xmlHttpObj = new ActiveXObject("Msxml2.XMLHTTP");

}

}

else

    xmlHttpObj = new XMLHttpRequest();

     return xmlHttp;

}

以后再要使用XMLHTTPRequest对象,直接调用GetXmlHttpRequest方法即可。

2.向服务器发出请求

使用XMLHttpRequest对象向Web服务器发出请求非常简捷。只需要提供要请求的URL地址(要求请求的URL页面能返回结构化的数据,不论是HTML格式还是XML格式)。下面的方法中,示例了如何使用XMLHttpRequest对象发送请求:

function  SyncXMLHttpCall()

{

    var xmlHttpObj;

    xmlHttpObj = GetXmlHttpRequest ();

    if (xmlHttpObj)

    {

        xmlHttpObj.open("GET","http://" + location.host +

         "//Data.xml", false);

        xmlHttpObj.send(null);

        alert("Request/Response Complete.");

    }

}

上面的代码非常简单,但是它演示了使用XMLHttpRequest对象向服务器发送请求的基本流程。来看看它是如何做的:

(1)声明变量xmlHttpObj用来存放自GetXmlHttpRequest方法得到的XMLHttpRequest对象。

(2)在检查了xmlHttpObj不为空,即成功获取了XMLHttpRequest对象之后,使用XMLHttpRequest对象的open方法,传递参数“GET”、服务器页面的URL字符串和一个布尔值。

(3)调用send方法发送请求。

(4)上面的这段代码采用同步发送请求的方式,在调用send方法之后,浏览器必须等待send方法返回以后才能继续。这就和传统的请求响应方式没有什么区别。

那么如何使用异步的方式发送请求呢?先来解释一下XMLHttpRequest对象的open方法的3个参数的意义:

l  第1个参数指定了HTTP请求的方式,可以是“GET”、“POST”、“PUT”和“HEAD”中的一个,在AJAX程序中,用的最多的是“GET”。

l  第2个参数是要请求的服务器页面的URL。在这个例子中,是服务器上一个XML文档。

l  第3个参数是布尔值。当这个参数为false时,请求发送采用同步的方式,反之就使用异步的方式发送请求。

下面的代码演示如何使用异步模式向服务器发送请求。

var xmlHttpObj=null;

function OnReadyStateChange()

{

    var ready=xmlHttpObj.readyState;

    var data=null;

     if(ready==READYSTATE_COMPLETE)

    {

        data=xmlHttpObj.responseText;

        alert(data);

    }

    else

    {

        document.write("请等待…");

    }

}

function asyncXMLHTTPCall()

{

    xmlHttpObj = GetXmlHttpRequest ();

    if (xmlHttpObj)

    {

      xmlHttpObj.open("GET","http:// " + location.host +

       "/DataFile.xml", true);

      xmlHttpObj.onreadystatechange =OnReadyStateChange;

      xmlHttpObj.send(null);

    }

}

在上面代码的asyncXMLHttpCall方法中,调用XMLHttpRequest对象的open方法,最后一个参数的值为true,表示了使用的是异步传送请求到服务器。注意xmlHttpObj.onreadystatechange=OnReadyStateChange;这个语句是用来注册一个回调方法来处理ReadyStateChange事件,这和C#的事件处理声明方法基本相同。当xmlHttpObj代表的请求的状态发生改变时,表示服务器有响应返回。当请求的状态改变,浏览器就会调用OnReadyStateChange方法来处理事件。在OnReadyStateChange方法中,首先检查请求的状态,查看其是否等于READYSTATE_COMPLETE,如果等于READYSTATE_COMPLETE则表示服务器正常响应了请求。请求可以有多个状态:

l  READYSTATE_UNINITIALIZED—默认的初始化状态。

l  READYSTATE_LOADING—对象正在载入它的属性。

l  READYSTATE_LOADED—对象初始化完成。

l  READYSTATE_INTERACTIVE—对象可以进行操作,但并非所有的数据都可用。

l  READYSTATE_COMPLETE—对象接收完所有的数据。

如果检查发现请求已经完成,则把响应的信息用alert方法显示在窗口中,否则在页面中显示“请等待…”的字样。

上面的示例演示了如何使用XMLHttpRequest对象与Web服务器进行异步的通信。实例中的代码在每个AJAX程序中都必不可少。XMLHttpRequest对象除了open和send方法以外,还有其他的一些相关方法,表15-1所示的是一个完整的XMLHttpRequest方法列表。

表15-1                                             XMLHttpRequest的方法列表

abort

取消当前的HTTP请求

getAllResponseHeaders

返回服务器响应信息所有的头部信息

getResponseHeader

返回服务器响应某一个头部信息

open

初始化一个XMLHttpRequest请求对象,并指定请求的路径、请求发送的方式和同步/异步模式

send

发送请求到Web服务器,并获取服务器的响应信息

setRequestHeader

设定请求的头信息

下面对这些方法进行解释。

l  open方法的原型是open(string method, string url, boolean asynch, string username, string password):这个方法初始化发向服务器的请求信息。它包含两个必需的参数和三个可选参数。使用这个方法必须提供服务器的URL和关于请求发送方式(一般为POST、GET和PUT三种之一)。可选参数中,第一个参数指定是否按异步模式进行请求,默认值是true;然后,如果服务器需要验证用户名和密码,那么还需要传递用户名和密码的参数。

l  send(content)方法:这个方法执行实际的请求发送操作。如果请求的类型是异步的,那么send方法立刻返回,反之send方法会等待直到收到服务器的响应以后才返回。send方法有一个可选的参数,参数的类型可以是一个DOM对象,也可以是一个输入流或者是一个字符串,参数的内容将被作为请求的body的一部分传送给服务器。

l  abort方法:按照字面意义理解即可。abort方法在收到服务器响应之前,立刻终止   请求。

l  setRequestHeader(string header, string value)方法:方法为指定的Header元素指派一个值。这个方法必须在open方法调用之后使用。

l  getAllResponseHeaders方法:获取响应中所有的Header信息。

l  getResponseHeader(string header):方法获取响应中指定header的信息。

XMLHttpRequest对象除了这些方法,还有一些公共的属性可以使用,表15-2列出了所有可用的属性:

表15-2                                                             可用的属性

onreadystatechange

为readystate属性发生变化时,指定一个事件处理方法

readyState

代表属性的状态。只读

responseBody

服务器响应信息的形式之一

responseStream

服务器响应信息的形式之一

responseText

服务器响应的具体信息

responseXML

服务器响应的具体信息。如果响应内容的content-type为xml,那么这个属性有值

status

HTTP状态值

statusText

HTTP状态文本

15.2.5  AJAX应用示例

在前面的几个小节介绍了AJAX的核心概念之后,在本节通过一个小型的AJAX应用让读者对AJAX有更进一步的理解。下面例子模仿互联网上众多站点中的注册模块的功能,并用AJAX来实现注册功能。

首先,用Visual Studio 2005新建一个空白站点,如图15-5所示。

图15-5  新建空白站点

在解决方案浏览器中,为站点添加一个HTML页面—signup.htm。简单地设计signup.htm页面,如图15-6所示。

图15-6  signup.htm页面设计图

signup.htm页面的HTML代码如下所示:

<!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>Untitled Page</title>

    <script type="text/javascript" language="javascript" src="JScript.js">      

    </script>

</head>

<body style="font-size: 12pt" bgcolor="#ffffff">

    <span style="color: #33cc33"><span style="font-family: 华文新魏">新用户注册:</span><br />

    </span>

    <div id="regdiv" style="width:401px;Height:149px;float:left;background-color: AliceBlue; text-align: center; border-right: #99cccc 1px solid; border-top: #99cccc 1px solid; border-left: #99cccc 1px solid; border-bottom: #99cccc 1px solid;">

        <div style="width: 250px; height: 24px;float:left; text-align: left; border-top-width: 1px; border-bottom-width: 1px; border-bottom-color: black; border-top-color: black;" id="DIV1">

            <span style="font-size: 10pt">用户名:</span><input id="username" name="username" style="width: 120px; left: 14px; position: relative; top: 2px; height: 14px;" type="text" /></div>

        <div style="width: 150px; height: 24px;float:left; text-align: center; border-top-width: 1px; border-bottom-width: 1px; border-bottom-color: black; border-top-color: black;">

            <input id="verifyusername" type="button" value="验证用户名" οnclick="userbtnClick();" style="border-right: silver thin solid; border-top: silver thin solid; border-left: silver thin solid; width: 79px; border-bottom: silver thin solid; height: 21px" /></div>

         <div style="width: 250px; height: 24px;float:left; text-align: left;">

             <span style="font-size: 10pt">密码<span style="font-size: 12pt">:</span></span><input id="password" style="width: 120px; font-size: 12pt; left: 24px; position: relative; top: 2px; height: 14px;"

                 type="password" name="password" /></div>

        <div style="width: 150px; height: 24px;float:left; font-size: 12pt;">

        </div>

         <div style="width: 250px; height: 24px;float:left; text-align: left; font-size: 12pt;">

             <span style="font-size: 10pt">重复密码:<input id="password2" style="width: 120px; position: relative; top: 2px; height: 14px;" type="password" name="password2" /></span></div>

        <div style="width: 150px; height: 24px;float:left">

        </div>

         <div style="width: 250px; height: 24px;float:left; text-align: left;">

             <span style="font-size: 10pt">电子邮件:<input id="emailtext" style="width: 120px" type="text" name="emailtext" /></span></div>

        <div style="width: 150px; height: 24px;float:left; text-align: center;"><input id="verifyemailBtn" type="button" value="验证Email是否可用" οnclick="emailbtnClick();" style="border-right: silver thin solid; border-top: silver thin solid; border-left: silver thin solid; width: 135px; border-bottom: silver thin solid; height: 21px" /></div>

        <div id="infodiv" style="width: 400px; height: 24px;float:left; text-align: left;"></div>

       

        <input id="signupbtn" name="signupbtn" style="position: relative; top: 4px; height: 21px"

            type="button" value="注册" οnclick="signupBtnClick();"/>

     </div>

</body>

</html>

signup.htm页面主要使用DIV标签来建立表格,因此在页面的HTML代码中不会存在<TABLE>、<TR>和<TD>标签。DIV标签更适合与层叠样式表的配合使用。虽然本例中只使用了内联的样式,但是可以很方便地转换为外置样式表方式。在页面中,有三个按钮,分别执行检查邮件的是否合法、用户名是否合法以及注册功能。这三个按钮所引发的操作将通过AJAX来完成。

为了让服务器端能为浏览器的XMLHttpRequest对象的请求提供数据,因此这里先创建了一个Web Service,来为客户端提供数据。在站点的解决方案浏览器中添加adduser.asmx这个web service。adduser.asmx的代码如下所示:

[WebService(Namespace = "http://tempuri.org/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class adduser : System.Web.Services.WebService {

    public adduser () {

        //Uncomment the following line if using designed components

        //InitializeComponent();

    }

    [WebMethod]

    public bool verifyEmail(string email)

    {

        System.Threading.Thread.Sleep(2000);

        if (email.Contains("@"))

            return true;

        else

            return false;

    }

    [WebMethod]

    public bool verifyUserName(string username)

    {

        System.Threading.Thread.Sleep(2000);

        return true;

    }

    [WebMethod]

    public bool createUser(string username,string password,string email)

    {

        System.Threading.Thread.Sleep(2000);

        return true;

    }   

}

adduser..asmx的代码中包含了3个方法:vefifyEmail(string email)、verifyUserName(string username)和createUser(string username, string password, string email)。为了简便,没有执行具体的数据库操作来真正地添加用户,查找用户。这个示例主要是为了演示AJAX的使用。

有了Web Service作为服务器端的数据源,现在要做的就是实现AJAX的代码。在解决方案中添加一个JavaScript文件—Jscript.js。Jscript.js代码如下:

    var http=GetXmlHttpRequestObject();   

    function GetXmlHttpRequestObject()

    {

        var xmlHttpObj=null;

        if (window.ActiveXObject)

        {

            try

            {

                xmlHttpObj = new ActiveXObject("Microsoft.XMLHTTP");

            }

            catch (e)

            {

                xmlHttpObj = new ActiveXObject("Msxml2.XMLHTTP");

            }

        }

        else

            xmlHttpObj = new XMLHttpRequest();

        return xmlHttpObj;

    }

    function CheckEmailAvailable(url,email,element)

    {

        var okmsg="<font style='font-weight:normal;color:green;position:relative; top:3px'>恭喜您,该邮件还没有被使用</font>";

        var failmsg="<font style='font-weight:normal;color:black;position: relative;top:3px'>该邮件地址已经注册过,请尝试其他的</font>";

        var waitmsg="请稍候... ...";

        http.open("POST",url,true);

        http.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

        {

            http.onreadystatechange=function()

            {

                if(http.readyState==4)

                {              

                    if(http.status==200)

                    {

                        var ret=http.ResponseXml.selectSingleNode("boolean/text()").text;

                        if(ret=='true')

                        {

                            document.getElementById(element).innerHTML=okmsg;

                        }

                        else

                            document.getElementById(element).innerHTML=failmsg+ret;

                       

                    }

                }

                else

                {

                    document.getElementById(element).innerHTML=waitmsg;

                };

            };

            http.send("email="+email);

        }

    };

    function emailbtnClick()

    {

        if(document.getElementById("emailtext").value=="")

        {

            alert("请填写邮件地址");

            return;

        }

        var url="/AJAXDemo/adduser.asmx/verifyEmail";

        var email=document.getElementById("emailtext").value;

        CheckEmailAvailable(url,email,"infodiv");

    }

   

     function CheckUserNameAvailable(url,username,element)

    {

        var okmsg="<font style='font-size:10px;font-weight:normal;color:green; position:relative;top:3px'>恭喜您,该用户名还没有被使用</font>";

        var failmsg="<font style='font-size:10px;font-weight:normal;color:black; position:relative;top:3px'>该用户名已经注册过,请尝试其他的</font>";

        var waitmsg="请稍候... ...";

        http.open("POST",url,true);

        http.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

        {

            http.onreadystatechange=function()

            {

                if(http.readyState==4)

                {              

                    if(http.status==200)

                    {

                        var ret=http.ResponseXml.selectSingleNode("boolean/text()").text;

                        if(ret=='true')

                        {

                            document.getElementById(element).innerHTML=okmsg;

                        }

                        else

                            document.getElementById(element).innerHTML=failmsg+ret;

                       

                    }

                }

                else

                {

                    document.getElementById(element).innerHTML=waitmsg;

                };

            };

            http.send("username="+username);

        }

    };

   

     function userbtnClick()

    {

        if(document.getElementById("username").value=="")

        {

            alert("请填写用户名");

            return;

        }

        var url="/AJAXDemo/adduser.asmx/verifyUserName";

        var username=document.getElementById("username").value;

        CheckUserNameAvailable(url,username,"infodiv");

    }

   

    function signupNewUser(url,element,username,password,email)

    {       

        var failmsg="<font style='font-size:10px;font-weight:normal;color: black;position:relative;top:3px'>注册失败</font>";

        var waitmsg="请稍候... ...";

        http.open("POST",url,true);

        http.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

        {

            http.onreadystatechange=function()

            {

                if(http.readyState==4)

                {              

                    if(http.status==200)

                    {

                        var ret=http.ResponseXml.selectSingleNode("boolean/text()").text;

                        if(ret=='true')

                        {

                            document.getElementById("regdiv").visible=false;

                            document.getElementById("regdiv").removeNode(true);

                            var divelement=document.createElement("DIV");

                            divelement.style.cssText="width:200px;height:100px;background-color:#ccff66;text-align:center";

                            divelement.innerHTML="<span style='color:blue;position:relative;top:35px'>注册成功!</span>";

                            document.body.appendChild(divelement);

                           

                        }

                        else

                            document.getElementById(element).innerHTML=failmsg;

                       

                    }

                }

                else

                {

                    document.getElementById(element).innerHTML=waitmsg;

                }

            }

            http.send("username="+username+"&password="+password+"&email="+email);

        }

    };

   

    function signupBtnClick()

    {

        var url="/AJAXDemo/adduser.asmx/createUser";

        var username=document.getElementById("username").value;

        var password=document.getElementById("password").value;

        var password2=document.getElementById("password2").value;

        var email=document.getElementById("emailtext").value;

        var element="infodiv";

        if(password!=password2)

        {

            alert("密码不一致");

            return;

        }

        if(username==null)

        {

            alert("请填写用户名");

            return;

        }

        if(email==null)

        {

            alert("请填写电子邮件");

            return;

        }

       

        signupNewUser(url,element,username,password,email);

       

    };

上面的代码保存在附赠光盘的“第15章/AJAXDemo/jscript.js”文件中。

上面就是Jscript.js文件中所有的代码。下面对代码中的方法进行解释:

(1)GetXmlHttpRequestObject()方法:该方法返回一个XMLHttpRequest对象。在本例中,使用全局变量http来保存这个XMLHttpRequest对象。GetXmlHttpRequestObject方法使用了之前讲到的XMLHttpRequest对象的创建方法。

(2)CheckEmailAvailable(url,email,element)方法。该方法向参数url指定的地址发出请求来验证由email参数指定的邮件地址。在这个方法中,按照XMLHttpRequest对象发送异步请求的步骤向服务器发送请求。首先,在方法中调用了XMLHttpRequest对象的open方法初始化请求;接着设定请求的Header信息;然后,为readystatechange事件注册事件处理方法。这里使用了Javascript的内部方法,与C# 2.0中的匿名方法非常类似。在匿名方法的内部,检查XMLHttpRequest的状态,如果不是处于完成状态,则使用CheckEmailAvailable方法的element参数传入的HTML元素,在这个HTML标签之内显示“请等待”的信息。当readystate为完成状态以后,通过XMLHttpRequest对象的ResponseXML属性获取响应信息。通过响应信息的结果,来判断是否当前输入的邮件地址可用。如果可用,显示恭喜的信息,反之显示红色的信息通知用户,邮件地址不可用。

图15-7所示是请求验证时页面显示的信息。

图15-8所示的是邮件地址不可用时所显示的信息。

图15-9所示是邮件地址顺利通过验证的情景。

图15-7  等待信息

       

           图15-8  邮件地址有问题                           图15-9  邮件地址通过验证

(3)function emailbtnClick()方法:该方法处理“验证emai是否可用”按钮的点击事件。在该方法内部,以email的输入值和服务器上对应的url作为参数,调用CheckEmailAvailable方法。

(4)function CheckUserNameAvailable(url,username,element)方法:该方法的工作原理与CheckEmailAvailable方法相同,也是通过XMLHttpRequest对象的异步请求与服务器通信验证用户名。

(5)function signupNewUser(url,element,username,password,email)方法:该方法仍然是通过XMLHttpRequest来异步的请求服务器,它把用户名、密码和邮件地址作为请求的一部分传递给服务器的Web Service。如果注册成功Web Service会返回一个“true”的结果。成功以后,代码删除注册模块所在的DIV标签,加入新的DIV标签用来显示注册成功的信息。

这个例子演示一个最基本的AJAX应用,仅仅是简单的通过XMLHttpRequest发送请求,并接受响应的结果,再通过Javascript来操作DOM显示结果。复杂的应用可能还涉及到异步通信队列的问题。由于,每个页面同一时刻只能有两个请求通过XMLHttpRequest对象发出,如果页面中包含大量的异步请求需要发送,那么还需要人工实现请求的排队。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值