Ajax全称为“Asynchronous JavaScript and XML”(异步JavaScript和XML),它并不是指一种单一的技术,而是有机地利用了一系列交互式网页应用相关的技术所形成的结合体。它的出现,揭开了无刷新更新页面的新时代,并有代替传统的Web方式和通过隐藏的框架来进行异步提交的趋势,是Web开发应用的一个里程碑。
6.1 Ajax的优势和不足
6.1.1 Ajax的优势
1.不需要插件支持
Ajax不需要任何浏览器插件,就可以被绝大多数主流浏览器所支持,用户只需要允许JavaScript在浏览器上执行即可。
2.优秀的用户体验
这是Ajax技术的最大优点,能在不刷新整个页面的前提下更新数据,这使得Web应用程序能更为迅速地回应用户的操作。
3.提高Web程序的性能
与传统模式相比,Ajax模式在性能上的最大区别就在于传输数据的方式,在传统模式中,数据提交是通过表单(Form)来实现的,而数据获取是靠全页面刷新来重新获取整页的内容。Ajax模式只是通过XMLHttpRequest对象向服务器端提交希望提交的数据,即按需发送。
4.减轻服务器和带宽的负担
Ajax的工作原理相当于在用户和服务器之间加了一个中间层,使用户操作与服务器响应异步化。它在客户端创建Ajax引擎,把传统方式下的一些服务器负担的工作转移到客户端,便于客户端资源来处理,减轻服务器和带宽的负担。
6.1.2 Ajax的不足
世界上并没有完美的事物,同样Ajax也并不是一项非常完美的技术。Ajax主要有以下几点不足之处。
1.浏览器对XMLHttpRequest对象的支持度不足
Ajax的不足之一首先来自于浏览器。Internet Explorer在5.0及以后的版本才支持XMLHttpRequest对象(现阶段大部分客户端上的IE浏览器是IE 6及以上),Mozilla、Netscape等浏览器支持XMLHttpRequest则更在其后。为了使得Ajax应用能在各个浏览器中正常运行,程序员必须花费大量的精力编码以兼顾各个浏览器之间的差别,来让Ajax应用能够很好地兼容各个浏览器。这使得Ajax开发的难度比普通的Web开发高出很多,许多程序员因此对Ajax望而生畏。
2.破坏浏览器前进、"后退"按钮的正常功能
在传统的网页中,用户经常会习惯性的使用浏览器自带的“前进”和“后退”按钮,然而Ajax改变了此Web浏览习惯。在Ajax中“前进”和“后退”按钮的功能都会失效,虽然可以通过一定的方法(添加锚点)来使得用户可以使用“前进”和“后退”按钮,但相对于传统的方式却麻烦了很多,对于大多数程序员来说宁可放弃前进、后退的功能,也不愿意在繁琐的逻辑中去处理该问题。然而,对于用户来说,他们经常会碰到这种情况,当单击一个按钮触发一个Ajax交互后又觉得不想这样做,接着就去习惯性地单击“后退”按钮,结果发生了最不愿意看到的结果,浏览器后退到了先前的一个页面,通过Ajax交互得到的内容完全消失了。
3.对搜索引擎的支持的不足
对于搜索引擎的支持也是Ajax的一项缺憾。通常搜索引擎都是通过爬虫程序来对互联网上的数以亿计的海量数据来进行搜索整理的,然而爬虫程序现在还不能理解那些奇怪的JavaScript代码和因此引起的页面内容的变化,这使得应用Ajax的站点在网络推广上相对于传统站点明显处于劣势。
4.开发和调试工具的缺乏
JavaScript是Ajax的重要组成部分,在目前,由于缺少很好的JavaScript开发和调试工具,使很多Web开发者对JavaScript望而生畏,这对于编写Ajax代码就更加困难了。同时,目前许多Web开发者已经习惯使用可视化的工具,对亲自动手编写代码有畏惧感,这也在一定程度上影响了大家对Ajax的应用。
6.2 Ajax的XMLHttpRequest对象
Ajax的核心是XMLHttpRequest对象,它是Ajax实现的关键——发送异步请求、接收响应及执行回调都是通过它来完成的。XMLHttpRequest对象最早是在Microsoft Internet Explorer 5.0 ActiveX组件中被引入的,之后各大浏览器厂商都以JavaScript内置对象的方式来实现XMLHttpRequest对象。虽然大家对它的实现方式有所区别,但是绝大多数浏览器都提供了类似的属性和方法,而且在实际脚本编写方法上的区别也不大,实现得到的效果也基本相同。目前W3C组织正致力于制定一个各浏览器厂商可以统一遵照执行的XMLHttpRequest对象标准,用来推进Ajax技术的推广与发展。
XMLHttpRequest对象提供了一个相对精简易用的API,本书在附录C中进行了详细介绍,读者可以自行查看。
6.3 安装Web环境——AppServ
由于讲解后面的Ajax方法需要与Web服务器端进行交互,因此这里将引用一个工具包——AppServ,它是PHP网页架站工具组合包,能够帮助初学者快速完成网页架站。AppServ所包含的软件有Apache、Apache Monitor、PHP、MySQL、PHP-Nuk和phpMy Admin。
1.下载AppServ
下载地址为:http://www.appservnetwork.com。
2.安装AppServ
安装AppServ非常简单,只要连续轻松地单击“Next”按钮,输入网址、电子邮箱、密码等常用信息即可。端口默认为80,当然也可以在安装时进行修改。
3.配置示例程序
将本书提供的示例程序复制到安装好后的AppServ/www文件夹中,然后在地址栏输入“http://localhost/Ch6/php/”,即可显示图6-1所示的页面。
图6-1 AppServ下的Ajax示例
单击相应文件夹,选定HTML页面,即可运行相应的Ajax示例。
注意:本书还提供了另外两种主流语言JSP和ASP编写的对应的示例程序,读者可以自行配置相应环境进行测试和学习。
6.4 编写第1个Ajax例子
在正式接触jQuery的Ajax操作之前,先看一个用传统的JavaScript实现的Ajax例子。例子描述:单击一个按钮,然后通过传统的JavaScript的Ajax的方式从服务器端取回一个“Hello Ajax!”的字符串并显示在页面上。
首先在前台页面中书写HTML代码,代码如下:
<button>按钮用来触发Ajax,id为“resText”的元素用来显示从服务器返回的HTML文本。
接下来的任务就是完成Ajax函数,实现步骤如下。
(1)定义一个函数,通过该函数来异步获取信息,代码如下:
(2)声明一个空对象用来装入XMLHttpRequest对象,代码如下:
(3)给XMLHttpRequest对象赋值,代码如下:
IE 5、IE 6是以ActiveXObject的方式引入XMLHttpRequest对象的,而其他浏览器的XMLHttpRequest对象是window的子对象。
(4)实例化成功后,使用open方法初始化XMLHttpRequest对象,指定HTTP方法和要使用的服务器URL,代码如下:
默认情况下,使用XMLHttpRequest对象发送的HTTP请求是异步进行的,但是可以显式地把async参数设置为true,如上面代码所示。
(5)因为要做一个异步调用,所以需要注册一个XMLHttpRequest对象将调用的回调事件处理器当它的readyState值改变时调用。当readyState值被改变时,会激发一个readystatechange事件,可以使用onreadystatechange属性来注册该回调事件处理器,代码如下:
(6)使用send方法发送该请求,因为这个请求使用的是HTTP的GET方式,所以可以在不指定参数或使用null参数的情况下调用send方法,代码如下:
当请求状态改变时,XMLHttpRequest对象调用onreadystatechange属性注册的事件处理器。因此,在处理该响应之前,事件处理器应该首先检查readyState的值和HTTP状态。当请求完成加载(readyState值为4)并且响应已经成功(HTTP状态值为200)时,就可以调用一个JavaScript函数来处理该响应内容,代码如下:
最后,如果单击“Ajax提交”按钮后发现网页上出现了“Hello Ajax!”,那么就完成了第1个Ajax调用。如图6-2所示。
图6-2 第1个Ajax示例
以上就是实现XMLHttpRequest对象使用的所有细节,它不必将Web页面的所有内容都发送到服务器,而是按需发送。使用JavaScript启动一个请求并处理相应的返回值,然后使用浏览器的DOM方法更新页面中的数据。显然,这种无刷新的模式能给网站带来更好的用户体验。但是XMLHttpRequest对象的很多属性和方法,对于想快速入门Ajax的人来说,似乎并不是个容易的过程。
幸运的是,jQuery提供了一些日常开发中需要的快捷操作,例如load、ajax、get和post等,使用jQuery开发Ajax将变得极其简单。这样开发人员就可以将程序开发集中在业务和用户体验上,而不需要理会那些繁琐的XMLHttpRequest对象。下面开始介绍jQuery中的Ajax。
6.5 jQuery中的Ajax
jQuery对Ajax操作进行了封装,在jQuery中$.ajax方法属于最底层的方法,第2层是load、$.get和$.post方法,第3层是$.getScript和$.getJSON方法。首先介绍第2层的方法,因为其使用频率很高。
6.5.1 load方法
1.载入HTML文档
load方法是jQuery中最为简单和常用的Ajax方法,能载入远程HTML代码并插入DOM中。它的结构为:
load方法参数解释如表6-1所示。
表6-1 load方法参数解释
参 数 名 称类 型说 明urlString请求HTML页面的URL地址data(可选)Object发送至服务器的key/value数据callback(可选)Function请求完成时的回调函数,无论请求成功或失败首先构建一个被load方法加载并追加到页面中的HTML文件,名字为test.html,HTML代码如下:
然后新建一个空白页面,在上面添加两个元素:<button>按钮用来触发Ajax事件,id为“resText”的元素用来显示追加的HTML内容。HTML代码如下:
接下来就可以开始编写jQuery代码了。等DOM元素加载完毕后,通过单击id为“send”的按钮来调用load方法,然后将test.html的内容加载到id为“resText”的元素里。
jQuery代码如下:
当按钮被单击后,出现图6-3所示的界面。
显然,load方法完成了原本很繁琐的工作。开发人员只需要使用jQuery选择器为HTML片段指定目标位置,然后将要加载的文件的URL作为参数传递给load方法即可。当单击按钮后,test.html页面的HTML内容就会被加载并插入主页面<p></p>的元素中。
注意:test.html页面里并没有添加样式,但现在加载的内容有样式了。这些样式是在主页面中添加的,即主页面相应的样式会立即应用到新加载的内容上。
2.筛选载入的HTML文档
上个例子是将test.html页面中的内容都加载到id为“resText”的元素里。如果只需要加载test.html页面内的某些元素,那么可以使用load方法的URL参数来达到目的。通过为URL参数指定选择符,就可以很方便地从加载过来的HTML文档里筛选出所需要的内容。
load方法的URL参数的语法结构为:"url selector"。注意,URL和选择器之间有一个空格。
例如只需要加载test.html页面中class为“para”的内容,可以使用如下代码来完成:
运行效果如图6-4所示。
3.传递方式
load方法的传递方式根据参数data来自动指定。如果没有参数传递,则采用GET方式传递;反之,则会自动转换为POST方式。关于GET和POST传递方式的区别,将在后面进行讲解。
图6-3 load方法调用成功
图6-4 用load方法加载一部分HTML元素
4.回调参数
对于必须在加载完成后才能继续的操作,load方法提供了回调函数(callback),该函数有3个参数,分别代表请求返回的内容、请求状态和XMLHttpRequest对象,jQuery代码如下:
注意:在load方法中,无论Ajax请求是否成功,只要当请求完成(complete)后,回调函数(callback)就被触发。对应下面将介绍的$.ajax方法中的complete回调函数。
6.5.2 $.get方法和$.post方法
load方法通常用来从Web服务器上获取静态的数据文件,然而这并不能体现Ajax的全部价值。在项目中,如果需要传递一些参数给服务器中的页面,那么可以使用$.get或者$.post方法(或者是后面要讲解的$.ajax方法)。
注意:$.get和$.post方法是jQuery中的全局函数,而在此之前讲的jQuery方法都是对jQuery对象进行操作的。
1.$.get方法
$.get方法使用GET方式来进行异步请求。
它的结构为:
$.get方法参数解释如表6-2所示。
表6-2 $.get方法参数解释
参 数 名 称类 型说 明urlString请求的HTML页的URL地址data(可选)Object发送至服务器的key/value数据会作为QueryString附加到请求URL中callback(可选)Function载入成功时回调函数(只有当Response的返回状态是success才调用该 方法)自动将请求结果和状态传递给该方法type(可选)String服务器端返回内容的格式,包括xml、html、script、json、text和_default下面是一个评论页面的HTML代码,通过该段代码来介绍$.get方法的使用。
本段代码将生成图6-5所示的页面。
将姓名和内容填写好后,就可以准备提交评论了。如图6-6所示。
图6-5 评论初始化页面
图6-6 填写好数据
(1)使用参数
首先,需要确定请求页面的URL地址。代码如下:
然后,在提交之前,需要获取“姓名”和“内容”的值作为data参数传递给后台。
代码如下:
如果服务器端接收到传递的data数据并成功返回,那么就可以通过回调函数将返回的数据显示到页面上。
$.get方法的回调函数只有两个参数,代码如下:
data参数代表请求返回的内容,textStatus参数代表请求状态,而且回调函数只有当数据成功返回(success)后才被调用,这点与load方法不一样。
(2)数据格式
服务器返回的数据格式可以有多种,它们都可以完成同样的任务。以下是几种返回格式的对比。
HTML片段
由于服务器端返回的数据格式是HTML片段,因此并不需要经过处理就可以将新的HTML数据插入到主页面中。jQuery代码如下:
HTML片段实现起来只需要很少的工作量,但这种固定的数据结构并不一定能够在其他的Web应用程序中得到重用。
XML文档
由于服务器端返回的数据格式是XML文档,因此需要对返回的数据进行处理,前面的章节已经介绍过jQuery强大的DOM处理能力,处理XML文档与处理HTML文档一样,也可以使用常规的attr、find、filter以及其他方法。jQuery代码如下:
返回数据格式为XML文档的过程实现起来比HTML片段要稍微复杂些,但XML文档的可移植性是其他数据格式无法比拟的,因此以这种格式提供的数据的重用性将极大提高。例如del.icio.us(http://del.icio.us),Flickr(http://flickr.com)和某些开放平台都是以XML格式输出数据,读者可以利用它们提供的API,将获得的内容整合到自己的网站中(Mashup应用)。不过,XML文档体积相对较大,与其他文件格式相比,解析和操作它们的速度要慢一些。
注意:由于期待服务器端返回的数据格式是XML文档,因此需要在服务端设置Content-Type类型,代码如下:header("Content-Type:text/xml; charset=utf-8"); // php
JSON文件
之所以会出现这种数据格式的文件,很大程度上是因为XML文档体积大和难以解析。JSON文件和XML文档一样,也可以方便的被重用。而且,JSON文件非常简洁,也容易阅读。想了解更多的JSON文档知识,可以访问http://json.org/网址。
由于服务器端返回的数据格式是JSON文件,因此需要对返回的数据进行处理之后,才可以将新的HTML数据添加到主页面中。jQuery代码如下:
在上面的代码中,将$.get方法的第4个参数(type)设置为“json”来代表期待服务器端返回的数据格式。
注意:(1)在不远的将来,新版的JavaScript中XML将会和JSON一样容易解析,相信到时候通用且容易解析的XML将会成为主流的数据交换格式。不过在它到来之前,JSON依然有很强的生命力。(2)JSON的格式非常严格,构建的JSON文件必须完整无误,任何一个括号的不匹配或者缺少逗号,都会导致页面上的脚本终止运行,甚至还会带来其他更加严重的负面影响。比如,我们返回的数据都必须要有双引号,必须是:{ "username" : "张三" },而不能是:{ username:"张三"}。
以上3种返回方式都可以达到图6-7所示的效果。
图6-7 将返回的数据添加到页面上
通过对3种数据格式的优缺点进行分析,可以得知在不需要与其他应用程序共享数据的时候,使用HTML片段来提供返回数据一般来说是最简单的;如果数据需要重用,那么JSON文件是不错的选择,它在性能和文件大小方面具有优势;而当远程应用程序未知时,XML文档是明智的选择,它是Web服务领域的“世界语”。具体选择哪种数据格式,并没有严格的规定,读者可以根据需求来选择最适合的返回格式来进行开发。
2.$.post方法
它与$.get方法的结构和使用方式都相同,不过它们之间仍然有以下区别。
GET请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器。当然,在Ajax请求中,这种区别对用户是不可见的。
GET方式对传输的数据有大小限制(通常不能大于2KB),而使用POST方式传递的数据量要比GET方式大得多(理论上不受限制)。
GET方式请求的数据会被浏览器缓存起来,因此其他人就可以从浏览器的历史记录中读取到这些数据,例如账号和密码等。在某种情况下,GET方式会带来严重的安全性问题,而POST方式相对来说就可以避免这些问题。
GET方式和POST方式传递的数据在服务器端的获取也不相同。在PHP中,GET方式的数据可以用$_GET获取,而POST方式可以用$_POST获取。两种方式都可以用$_REQUEST来获取。
由于POST和GET方式提交的所有数据都可以通过$_REQUEST来获取,因此只需要改变jQuery函数,就可以将程序在GET请求和POST请求之间切换。代码如下:
另外,当load方法带有参数传递时,会使用POST方式发送请求。因此也可以使用load方法来完成同样的功能。代码如下:
上面使用load、$.get和$.post方法完成了一些常规的Ajax程序,如果还需要编写一些复杂的Ajax程序,那么就要用到jQuery中的$.ajax方法。$.ajax方法不仅能实现与load、$.get和$.post方法同样的功能,而且还可以设定beforeSend(提交前回调函数)、error(请求失败后处理)、success(请求成功后处理)以及complete(请求完成后处理)回调函数,通过这些回调函数,可以给用户更多的Ajax提示信息。另外,还有一些参数,可以设置Ajax请求的超时时间或者页面的“最后更改”状态等。关于$.ajax方法将在后面的章节中进行讲解。
6.5.3 $.getScript方法和$.getJson方法
1.$.getScript
有时候,在页面初次加载时就取得所需的全部JavaScript文件是完全没有必要的。虽然可以在需要哪个JavaScript文件时,动态地创建<script>标签,jQuery代码如下:
或者
但这种方式并不理想。为此,jQuery提供了$.getScript方法来直接加载.js文件,与加载一个HTML片段一样简单方便,并且不需要对JavaScript文件进行处理,JavaScript文件会自动执行。
jQuery代码如下:
当“加载”按钮被单击后,出现如图6-8所示的效果。
图6-8 $.getScript('test.js')方法调用成功
与其他Ajax方法一样,$.getScript方法也有回调函数,它会在JavaScript文件成功载入后运行。例如想载入jQuery官方颜色动画插件(jquery.color.js),成功后给元素绑定颜色变化动画,就可以用到$.getScript方法的回调函数。代码如下:
当jquery.color.js动画插件加载完毕后,单击id为“go”按钮时,class为block的元素就有了颜色动画变化。
2.$.getJSON
$.getJSON0方法用于加载JSON文件,与$.getScript方法的用法相同。
jQuery代码如下:
当单击“加载”按钮后,网页上看不到任何效果。虽然函数加载了JS0N文件,但是并没有告诉JavaScript对返回的数据如何处理。为此,jQuery提供了回调函数,在回调函数里处理返回的数据。代码如下:
可以在函数中通过data变量来遍历相应的数据,也可以使用迭代方式为每个项构建相应的HTML代码。虽然在这里可以使用传统的for循环来实现,但既然是讲解jQuery,那么还是使用jQuery里的方法。jQuery提供了一个通用的遍历方法$.each,可以用于遍历对象和数组。
$.each函数不同于jQuery对象的each方法,它是一个全局函数,不操作jQuery对象,而是以一个数组或者对象作为第1个参数,以一个回调函数作为第2个参数。回调函数拥有两个参数:第1个为对象的成员或数组的索引,第2个为对应变量或内容。代码如下:
在上面的代码中,当返回数据成功后,首先清空id为“resText”的元素的内容,以便重新构造新的HTML,然后通过$.each循环函数依次遍历每个项,并将遍历出来的内容构建成HTML代码拼接起来,最后将构建好的HTML添加到id为“resText”的元素中。
当“加载”按钮被单击后,出现如图6-9所示的效果。
图6-9 $.getJSON('test.json')函数执行成功
不仅如此,还能通过使用JSONP形式的回调函数来加载其他网站的JSON数据,例如从图片网站(http://Flickr.com)搜索汽车类别的4张最新图片。代码如下:
上面的代码中再次用到全局函数$.each来遍历数据,因为只需要4张图片,所以当i=3的时候就需要退出循环。在$.each函数中,如果需要退出each循环,只要返回false即可。
当“加载”按钮被单击后,从Flickr网站加载的4张最新的汽车图片就会被添加到页面中。效果如图6-10所示。
图6-10 加载Flickr网站的图片
注意:(1)jQuery将自动把URL里的回调函数,例如“url?callback=?”中的后一个“?”替换为正确的函数名,以执行回调函数。(2)JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过JavaScript Callback的形式实现跨域访问。由于JSON只是一种含有简单括号结构的纯文本,因此许多通道都可以交换JSON消息。而由于同源策略的限制,开发人员不能在与外部服务器进行通信的时候使用XMLHttpRequest。而JSONP是一种可以绕过同源策略的方法,即通过使用JSON与<script>标记相结合的方法,从服务器端直接返回可执行的JavaScript函数调用或者JavaScript对象。目前JSONP已经成为各大公司的Web应用程序跨域首选,例如Youtube GData、Google Social Graph、Digg、豆瓣、Del.icio.us等。
6.5.4 $.ajax方法
$.ajax方法是jQuery最底层的Ajax实现。
它的结构为:
该方法只有1个参数,但在这个对象里包含了$.ajax方法所需要的请求设置以及回调函数等信息,参数以key/value的形式存在,所有参数都是可选的,常用参数如表6-3所示。
表6-3 $.ajax方法常用参数解释
如果需要使用$.ajax方法来进行Ajax开发,那么上面这些常用的参数都必须了解。此外,$.ajax方法还有其他参数,读者可以参考附录D的具体介绍。
前面用到的$.load、$.get、$.post、$.getScript和$.getJSON这些方法,都是基于$.ajax方法构建的,$.ajax方法是jQuery最底层的Ajax实现,因此可以用它来代替前面的所有方法。
例如,可以使用下面的jQuery代码代替$.getScript方法:
再例如,可以使用以下jQuery代码来代替$.getJSON方法:
6.6 序列化元素
1.serialize方法
做项目的过程中,表单是必不可少的,经常用来提供数据,例如注册、登录等。常规的方法是使表单提交到另一个页面,整个浏览器都会被刷新,而使用Ajax技术则能够异步地提交表单,并将服务器返回的数据显示在当前页面中。
前面在讲解$.get和$.post方法的时候,表单的HMTL代码如下:
为了获取姓名和内容,必须将字段的值逐个添加到data参数中。代码如下:
这种方式在只有少量字段的表单中,勉强还可以使用,但如果表单元素越来越复杂,使用这种方式在增大工作量的同时也使表单缺乏弹性。jQuery为这一常用的操作提供了一个简化的方法——serialize。与jQuery中其他方法一样,serialize方法也是作用于一个jQuery对象,它能够将DOM元素内容序列化为字符串,用于Ajax请求。通过使用serlialize方法,可以把刚才的jQuery代码改为如下:
当单击“提交”按钮后,也能达到同样的效果。如图6-11所示。
图6-11 使用serialize方法
即使在表单中再增加字段,脚本仍然能够使用,并且不需要做其他多余工作。
需要注意的是,$.get方法中data参数不仅可以使用映射方式,如以下jQuery代码:
也可以使用字符串方式,如以下jQuery代码:
用字符串方式时,需要注意对字符编码(中文问题),如果不希望编码带来麻烦,可以使用serialize方法,它会自动编码。
因为serialize方法作用于jQuery对象,所以不光只有表单能使用它,其他选择器选取的元素也都能使用它,如以下jQuery代码:
把复选框和单选框的值序列化为字符串形式,只会将选中的值序列化。
2.serializeArray方法
在jQuery中还有一个与serialize类似的方法——serializeArray,该方法不是返回字符串,而是将DOM元素序列化后,返回JSON格式的数据。jQuery代码如下:
通过console.log方法输出fields对象,然后在Firebug中查看该对象,如图6-12所示。
图6-12 用Firebug查看对象
既然是一个对象,那么就可以使用$.each函数对数据进行迭代输出。代码如下:
3.$.param方法
它是serialize方法的核心,用来对一个数组或对象按照key/value进行序列化。
比如将一个普通的对象序列化:
6.7 jQuery中的Ajax全局事件
jQuery简化Ajax操作不仅体现在调用Ajax方法和处理响应方面,而且还体现在对调用Ajax方法的过程中的HTTP请求的控制。通过jQuery提供的一些自定义全局函数,能够为各种与Ajax相关的事件注册回调函数。例如当Ajax请求开始时,会触发ajaxStart方法的回调函数;当Ajax请求结束时,会触发ajaxStop方法的回调函数。这些方法都是全局的方法,因此无论创建它们的代码位于何处,只要有Ajax请求发生时,就会触发它们。在前面例子中,远程读取Flickr.com网站的图片速度可能会比较慢,如果在加载的过程中,不给用户提供一些提示和反馈信息,很容易让用户误认为按钮单击无用,使用户对网站失去信心。
此时,就需要为网页添加一个提示信息,常用的提示信息是“加载中…”,代码如下:
然后用CSS控制元素隐藏,当Ajax请求开始的时候,将此元素显示,用来提示用户Ajax请求正在进行。当Ajax请求结束后,将此元素隐藏。代码如下:
这样一来,在Ajax请求过程中,只要图片还未加载完毕,就会一直显示“加载中…”的提示信息,看似很简单的一个改进,却将极大地改善用户的体验。效果如图6-13所示。
如果在此页面中的其他地方也使用Ajax,该提示信息仍然有效,因为它是全局的。如图6-14所示。
图6-13 显示"加载中…"的提示信息
图6-14 demo2也使用同一个提示信息
jQuery的Ajax全局事件中还有几个方法,也可以在使用Ajax方法的过程中为其带来方便。如表6-4所示。
表6-4 另外几个方法
方 法 名 称说 明ajaxComplete(callback)Ajax请求完成时执行的函数ajaxError(callback)Ajax请求发生错误时执行的函数,捕捉到的错误可以作为最后一个参数传递ajaxSend(callback)Ajax请求发送前执行的函数ajaxSuccess(callback)Ajax请求成功时执行的函数注意:1,如果想使某个Ajax请求不受全局方法的影响,那么可以在使用$.ajax(options)方法时,将参数中的global设置为false,jQuery代码如下:
2,在jQuery1.5版本之后,如果Ajax请求不触发全局方法,那么可以设置:
具体原因请查看:http://bugs.jquery.com/ticket/8338
6.8 基于jQuery的Ajax聊天室程序
通过前面的介绍,相信读者已经对jQuery的Ajax有了较深的认识。下面,将讲解一个较为复杂的Ajax实例,可以帮助读者更好地掌握Ajax的精髓——一个基于Ajax无需刷新技术开发的聊天室程序,该程序允许多用户在网页上聊天,并且可以实时地更新信息。
6.8.1 基本设想
首先设计聊天室的外观,如图6-15所示。
图6-15 聊天室外观
6.8.2 设计数据库
这里使用MySql数据库来存储信息。
首先构建一个聊天信息表messages,它有4个字段,即消息编号(id)、姓名(user)、内容(msg)以及一个数字时间戳(time)。下面是创建该表的SQL代码:
6.8.3 服务器端处理
服务器端主要用来处理用户提交的信息以及输出返回。
首先需要在服务器端链接数据库。
其次如果有用户提交新信息,则把信息插入数据库,同时删除旧的数据信息(保持数据库中只有10条信息)。
最后从数据库中获取新的信息并以XML格式输出返回。
这里可以先模拟服务端输出的XML代码结构,XML文档代码如下:
在这个XML结构中,不光只有消息的实体(包括作者及其聊天信息),还增加了一个“status”标签和一个“time”标签。其中“status”标签用来表示信息请求的状态,如果值为1,则表示新信息请求成功;如果值为2,则表示请求成功但没有新信息。“time”标签用来记录信息请求的时间,可以被用来读取该时间戳后用户提交的新数据。
6.8.4 客户端处理
在客户端需要做两项工作。
首先提交用户聊天信息,然后处理服务器端返回的聊天信息,将信息实时呈现出来。
每隔一定时间发起查询数据库中聊天记录的请求,然后处理服务端返回的聊天信息,将信息实时呈现出来。
(1)提交用户聊天信息
使用POST方式向服务器发送请求,将用户填写的姓名和内容等数据传递到服务器端,在服务器端处理后返回相应的XML数据,然后使用回调函数处理服务器端返回的这些数据,并将新信息追加到客户端的消息显示区中。
(2)浏览器每隔一定时间更新数据
增加一个定时器,并且每隔一定时间调用一次。然后使用回调函数处理服务器端返回的XML数据,并将新信息追加到客户端的消息显示区中。
由于上面的两项工作都需要对XML文档进行解析,然后追加到信息显示区,因此可以将此操作进行封装,以便于重复利用。在设计该XML文档操作函数时,应注意通过状态(“status”标签)和时间戳(“time”标签)来控制获取聊天信息。
6.8.5 客户端代码
1.客户端HTML代码
首先建立一个HTML页面。从前面的外观设计可以知道页面需要一个外围<p>、一个消息段落(用来显示聊天信息)、姓名文本框、消息文本、提交按钮的表单和一个加载信息时的提示。HTML代码如下:
当用户第1次进入聊天室的时候,显示效果如图6-16所示。
图6-16 初始化页面效果
2.客户端jQuery代码
首先,需要设置当前消息的时间戳为0,并且调用函数来加载数据库已有的聊天消息,代码如下:
然后,为表单添加一个submit事件,代码如下:
在submit事件函数中,可以使用jQuery的$.post方法来发送一个POST请求,把要传递的数据都放入第2个参数中,用{ }包裹,代码如下:
接下来,如何响应返回的XML呢?为了使代码能被重用,这里创建一个处理XML的函数并且调用该函数(在updateMsg方法中,也要用到这个解析XML的函数)。函数如下:
addMessages函数里的具体内容将在后边实现。
现在就可以列出表单提交的全部代码了,代码如下:
在表单提交事件的最后一行添加了“return false;”语句,可以用来阻止浏览器提交表单。
现在再看addMessages函数,它是用来处理XML响应信息的。前面讲解过,jQuery遍历XML文档与遍历DOM一样。使用XML文档中的状态码,其代码如下:
上段代码中使用$("status",xml)方法来通知jQuery去XML文档中寻找“status”标签。如果状
态代码为2,则表示完成了请求但没有新信息需要添加到该客户端的消息显示区中,因此使用“return;”语句终止函数调用。如果状态代码不为2,则继续往下执行。
接下来需要为XML的时间戳设定新的值,用来传递给后台去查询新的数据。获取时间戳的代码如下:
然后使用$.each函数将XML文档里的数据遍历出来。在示例中,需要显示到客户端消息显示区的元素就是服务器端返回的每一个“message”标签的实例,每个实例代表一条要显示的消息。以下代码展示如何遍历数据:
得到了所需的数据之后,就可以将其追加到消息显示区里。消息显示窗体的id为“messagewindow”,因此可以使用$("#messagewindow")来选择到它并且使用prepend方法来追加数据,代码如下:
将它们整合后,addMessages(xml)函数的代码如下:
最后,只剩下刚开始调用的函数updateMsg还未完成。该函数的功能是到服务器查询新信息,并且调用addMessages函数来响应返回的XML文档,同时需要设置一个间隔时间,让聊天窗口自动更新。要开始做这些工作,只需要向服务器提交一个时间戳,引用这个$.post调用即可,代码如下:
在回调函数里,首先应该移除loading消息,可以在这个元素上调用remove方法,代码如下:
然后,在回调函数中将接受到的XML文档对象传递给addMessages函数,代码如下:
最后调用JavaScript的setTimeout方法来每隔一定时间执行updateMsg函数。
updateMsg函数的代码如下:
6.8.6 整合代码
聊天界面如图6-17所示。
正如读者所看到的,仅用了少量的jQuery代码,就实现了一个完整的基于Ajax的Web聊天室应用程序。用jQuery可以如此简单的实现一个复杂的Ajax应用,不得不令人叹服。
图6-17 最终的聊天室程序
6.9 小结
本章首先对Ajax进行了简介,并且介绍了Ajax的优势与不足,让读者充分了解到Ajax的适用范围。接下来介绍了Ajax的XMLHttpRequest对象,并展示了传统的Ajax程序的编写,然后系统地讲解了jQuery中的Ajax方法。在介绍了序列化元素和Ajax全局事件两个重要的概念后,讲解了一个稍微复杂的Ajax聊天室程序。