jQuery 与 Ajax 的应用
Ajax 全称为 "Asynchronous JavaScript and XML"(异步 JavaScript 和 XML ),它并不是指一种单一的技术,而是有机地利用了一系列交互式网页应用相关的技术所形成的结合体。它的出现,揭开了无刷新更新页面的新时代,并有代替传统的 Web 方式和通过隐藏的框架来进行异步提交的趋势,是 Web 开发应用的一个里程碑。
编写第一个Ajax例子
在正式接触 jQuery 的 Ajax 操作之前,先看一个用传统的 JavaScript 实现的 Ajax 例子。例子描述:单击一个按钮,然后通过传统的 JavaScript 的 Ajax 的方式从服务器端取回一个 "Hello Ajax !" 的字符串并显示在页面上。
<script language="javascript" type="text/javascript"> //通过这个函数来异步获取信息 function Ajax(){ var xmlHttpReq = null; //声明一个空对象用来装入XMLHttpRequest if (window.ActiveXObject){//IE5 IE6是以ActiveXObject的方式引入XMLHttpRequest的 xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP"); }else if (window.XMLHttpRequest){//除IE5 IE6 以外的浏览器XMLHttpRequest是window的子对象 xmlHttpReq = new XMLHttpRequest();//实例化一个XMLHttpRequest } if(xmlHttpReq != null){ //如果对象实例化成功 xmlHttpReq.open("GET","test.jsp",true); //调用open()方法并采用异步方式 xmlHttpReq.onreadystatechange=RequestCallBack; //设置回调函数 xmlHttpReq.send(null); //因为使用get方式提交,所以可以使用null参调用 } function RequestCallBack(){//一旦readyState值改变,将会调用这个函数 if(xmlHttpReq.readyState == 4){ if(xmlHttpReq.status == 200){ //将xmlHttpReq.responseText的值赋给ID为 resText 的元素 document.getElementById("resText").innerHTML = xmlHttpReq.responseText; } } } } </script> <body> <input type="button" id="" value="Ajax提交" onclick="Ajax();" /> <div id="resText" ></div> </body>
因为要做一个异步调用,所以需要注册一个 XMLHttpRequest 对象将调用的回调事件处理器当它的 readyState 值改变时调用。当 readyState 值被改变时,会激发一个 readystatechange 事件,可以使用 onreadystatechange 属性来注册该回调事件处理器,代码如下:
xmlHttpReq.onreadystatechange=RequestCallBack; //设置回调函数
使用 send() 方法发送该请求,因为这个请求使用的是 HTTP 的 GET 方式,所以可以在不指定参数或使用 null 参数的情况下调用 send() 方法,代码如下:
xmlHttpReq.send(null); //因为使用get方式提交,所以可以使用null参调用
当请求状态改变时, XMLHttpRequest 对象调用 onreadystatechange 属性注册的事件处理器。因此,在处理该响应之前,事件处理器应该首先检查 readyState 的值和 HTTP 状态。当请求完成加载(readyState 值为4)并且响应已经成功(HTTP 状态值为200)时,就可以调用一个 JavaScript 函数来处理该响应内容,代码如下:
function RequestCallBack(){//一旦readyState值改变,将会调用这个函数
if(xmlHttpReq.readyState == 4){
if(xmlHttpReq.status == 200){
//将xmlHttpReq.responseText的值赋给ID为 resText 的元素
document.getElementById("resText").innerHTML = xmlHttpReq.responseText;
}
}
}
最后,如果单击 "Ajax 提交" 按钮后发现网页上出现了 "Hello Ajax !",那么就完成了第1个Ajax 调用。如下图所示。
以上就是实现 XMLHttpRequest 对象使用的所有细节,它不必将 Web 页面的所有内容都发送到服务器,而是按需发送。使用 JavaScript 启动一个请求并处理相应的返回值,然后使用浏览器的 DOM 方法更新页面中的数据。显然,这种无刷新的模式能给网站带来更好的用户体验。但是 XMLHttpRequest 对象的很多属性和方法,对于想快速入门 Ajax 的人来说,似乎并不是个容易的过程。
幸运的是, jQuery 提供了一些日常开发中需要的快捷操作,例如 load、 ajax、 get 和 post 等,使用 jQuery 开发 Ajax 将变得极其简单。这样开发人员就可以将程序开发集中在业务和用户体验上,而不需要理会那些繁琐的 XMLHttpRequest 对象。下面开始介绍 jQuery 中的 Ajax 。
jQuery 中的 Ajax
jQuery 对 Ajax 操作进行了封装,在 jQuery 中 $.ajax() 方法属于最底层的方法,第2层是 load()、$.get() 和 $.post() 方法,第3层是 $.getScript() 和 $.getJSON() 方法。首先介绍第2层的方法,因为其使用频率很高。
load() 方法
1.载入HTML文档
load() 方法是 jQuery 中最为简单和常用的 Ajax 方法,能载入远程 HTML 代码并插入 DOM 中。它的结构为:load( url [, data] [, callback] )
参数名称 | 类型 | 说明 |
url | String | 请求 HTML 页面的 URL 地址 |
data ( 可选) | Object | 发送至服务器的 key/value 数据 |
callback ( 可选) | Function | 请求完成时的回调函数,无论请求成功或失败 |
首先构建一个被 load() 方法加载并追加到页面中的 HTML 文件,名字为 test.html, HTML 代码如下:
<body> <div class="comment"> <h6>张三:</h6> <p class="para">沙发.</p> </div> <div class="comment"> <h6>李四:</h6> <p class="para">板凳.</p> </div> <div class="comment"> <h6>王五:</h6> <p class="para">地板.</p> </div> </body>
然后新建一个空白页面,在上面添加两个元素:<button> 按钮用来触发 Ajax 事件, id 为 "resText" 的元素用来显示追加的 HTML 内容。 HTML 代码如下:
<script src="../scripts/jquery.js" type="text/javascript"></script> <script language="javascript" type="text/javascript"> $(function(){ $("#send").click(function(){ $("#resText").load("test.html"); }) }) </script> <body> <input type="button" id="send" value="Ajax获取" /> <div class="comment"> 已有评论: </div> <div id="resText" ></div> </body>
当按钮被单击后,出现下图所示的界面。
显然, load() 方法完成了原本很繁琐的工作。开发人员只需要使用 jQuery 选择器为 HTML 片段指定目标位置,然后将要加载的文件的 URL 作为参数传递给 load() 方法即可。当单击按钮后,test.html 页面的 HTML 内容就会被加载并插入主页面<div id="resText" ></div>的元素中。
注意: test.html 页面里并没有添加样式,但现在加载的内容有样式了,这些样式是在主页面中添加的,即主页面相应的样式会立即应用到新加载的内容上。
2.筛选载入的 HTML 文档
上个例子是将 test.html 页面中的内容都加载到 id 为"resText"的元素里。如果只需要加载 test.html 页面内的某些元素,那么可以使用 load() 方法的 URL 参数来达到目的。通过为 URL 参数指定选择符,就可以很方便地从加载过来的 HTML 文档里筛选出所需要的内容。
load() 方法的 URL 参数的语法结构为:"url selector"。注意, URL 和选择器之间有一个空格。
例如只需要加载 test.html 页面中 class 为"para"的内容,可以使用如下代码来完成:
<script language="javascript" type="text/javascript"> $(function(){ $("#send").click(function(){ $("#resText").load("test.html .para"); }) }) </script>
运行效果如下图所示。
3.传递方式
load() 方法的传递方式根据参数 data 来自动指定。如果没有参数传递,则釆用 GET 方式传递;反之,则会自动转换为 POST 方式。关于 GET 和 POST 传递方式的区别,将在后面进行讲解。
//无参数传递,则是GET方式
$("#resText").load("test.php", function(){
//...
});
//有参数传递,则是POST方式
$("#resText").load("test.php", {name : "rain", age : "22"}, function(){
//...
});
4.回调参数
对于必须在加载完成后才能继续的操作, load() 方法提供了回调函数(callback) ,该函数有3个参数,分别代表请求返回的内容、请求状态和 XMLHttpRequest 对象, jQuery 代码如下:
$("resText").load("test.html", function(responseText. textStatus, XMLHttpRequest){
// responseText : 请求返回的内容
// textStatus : 请求状态:success、error、notmodified、timeout 4 种
// XMLHttpRequest : XMLHttpRequest 对象
});
注意:在 load() 方法中,无论 Ajax 请求是否成功,只要当请求完成(complete)后,回调函数(callback)就被触发。对应下面将介绍的 $.ajax() 方法中的 complete 回调函数。
$.get() 方法和 $.post() 方法
load() 方法通常用来从 Web 服务器上获取静态的数据文件,然而这并不能体现 Ajax 的全部价值。在项目中,如果需要传递一些参数给服务器中的页面,那么可以使用 $.get() 方法和 $.post() 方法(或者是后面要讲解的 $.ajax() 方法)。
注意:$.get() 方法和 $.post() 方法是 jQuery 中的全局函数
$.get() 方法
$.get() 方法使用 GET 方式来进行异步请求。它的结构为:$.get( url [, data] [, callback] [, type])
参数名称 | 类型 | 说明 |
url | String | 请求的 HTML 页的 URL 地址 |
data (可选) | Object | 发送至服务器的 key / value 数据会作为 QueiyString 附加到请求 URL 中 |
callback (可选) | Function | 载入成功时回调函数(只有当 Response 的返回状态是 success 才调用该 方法)自动将请求结果和状态传递给该方法 |
type (可选) | String | 服务器端返回内容的格式,包括 xml、html、script、json、text 和_default |
下面是一个评论页面的 HTML 代码,通过该段代码来介绍 $.get() 方法的使用。
<form id="form1"> <p>评论:</p> <p>姓名: <input type="text" name="username" id="username" /></p> <p>内容: <textarea name="content" id="content" ></textarea></p> <p><input type="button" id="send" value="提交"/></p> </form> <div class='comment'>已有评论:</div> <div id="resText"></div>
(1) 使用参数
首先,需要确定请求页面的 URL 地址。代码如下:
<script language="javascript" > $(function(){ $("#send").click(function(){ $.get("get1.jsp", { username : encodeURI( $("#username").val() ) , content : encodeURI( $("#content").val() ) }, function (data, textStatus){ $("#resText").html( decodeURI(data) ); // 把返回的数据添加到页面上 } ); }) }) </script>
$.get() 方法的回调函数只有两个参数,代码如下:
function (data, textStatus){
//data : 返回的内容,可以是 XMl 文档、 JSON 文件、HTML片段等等
//textStatus : 请求状态: success 、 error 、 notmodified、timeout 4 种
}
data 参数代表请求返回的内容, textStatus 参数代表请求状态,而且回调函数只有当数据成功返回(success)后才被调用,这点与 load() 方法不一样。
(2) 数据格式
服务器返回的数据格式可以有多种,它们都可以完成同样的任务。以下是几种返回格式的对比。
① HTML 片段
由于服务器端返回的数据格式是 HTML 片段,因此并不需要经过处理就可以将新的 HTML 数据插入到主页面中。 jQuery 代码如下:
<script language="javascript" > $(function(){ $("#send").click(function(){ $.get("get1.jsp", { username : encodeURI( $("#username").val() ) , content : encodeURI( $("#content").val() ) }, function (data, textStatus){ $("#resText").html( decodeURI(data) ); // 把返回的数据添加到页面上 } ); }) }) </script>
HTML 片段实现起来只需要很少的工作量,但这种固定的数据结构并不一定能够在其他的 Web 应用程序中得到重用。
② XML 文档
由于服务器端返回的数据格式是 XML 文档,因此需要对返回的数据进行处理,jQuery 强大的 DOM 处理能力,处理 XML 文档与处理 HTML 文档一样,也可以使用常规的 attr()、 find()、 filter() 以及其他方法。 jQuery 代码如下:
<script language="javascript" > $(function(){ $("#send").click(function(){ $.get("get2.jsp", { username : encodeURI( $("#username").val() ) , content : encodeURI( $("#content").val() ) }, function (data, textStatus){ var username = $(data).find("comment").attr("username"); var content = $(data).find("comment content").text(); username = decodeURI(username); content = decodeURI(content); var txtHtml = "<div class='comment'><h6>"+username+":</h6><p class='para'>"+content+"</p></div>"; $("#resText").html(txtHtml); // 把返回的数据添加到页面上 }); }) }) </script>
返回数据格式为 XML 文档的过程实现起来比 HTML 片段要稍微复杂些,但 XML 文档的可移植性是其他数据格式无法比拟的,因此以这种格式提供的数据的重用性将极大提高。不过, XML 文档体积相对较大,与其他文件格式相比,解析和操作它们的速度要慢一些。
③ json 文件
之所以会出现这种数据格式的文件,很大程度上是因为 XML 文档体积大和难以解析 。JSON文件和 XML 文档一样,也可以方便的被重用。而且, JSON 文件非常简洁,也容易阅读。想了解更多的 JSON 文档知识,可以访问 http://json.org/ 网址。
由于服务器端返回的数据格式是 JSON 文件,因此需要对返回的数据进行处理之后,才可以将新的 HTML 数据添加到主页面中。 jQuery 代码如下:
<script language="javascript" > $(function(){ $("#send").click(function(){ $.get("get3.jsp", { username : encodeURI( $("#username").val() ) , content : encodeURI( $("#content").val() ) }, function (data, textStatus){ var username = data.username; var content = data.content; username = decodeURI(username); content = decodeURI(content); var txtHtml = "<div class='comment'><h6>"+username+":</h6><p class='para'>"+content+"</p></div>"; $("#resText").html(txtHtml); // 把返回的数据添加到页面上 },"json"); }) }) </script>
在上面的代码中,将 $.get() 方法的第4个参数 (type) 设置为 "json" 来代表期待服务器端返回的数据格式。
注意:
(1)在不远的将来,新版的 JavaScript 中 XML 将会和 JSON —样容易解析,相信到时候通用且容易解析的 XML 将会成为主流的数据交换格式。不过在它到来之前, JSON 依然有很强的生命力。
(2)JSON 的格式非常严格,构建的 JSON 文件必须完整无误,任何一个括号的不匹配或者缺少逗号,都会导致页面上的脚本终止运行,甚至还会带来其他更加严重的负面影响。比如,我们返回的数据都必须要有双引号,必须是:{"username" : " 张三"},而不能是:{username : " 张三"}
以上3种返回方式都可以达到下图所示的效果。
通过对3种数据格式的优缺点进行分析,可以得知在不需要与其他应用程序共享数据的时候,使用 HTML 片段来提供返回数据一般来说是最简单的;如果数据需要重用,那么 JSON文件是不错的选择,它在性能和文件大小方面具有优势;而当远程应用程序未知时, XML 文档是明智的选择,它是 Web 服务领域的"世界语"。具体选择哪种数据格式,并没有严格的规定,读者可以根据需求来选择最适合的返回格式来进行开发。
$.post() 方法
它与 $.get() 方法的结构和使用方式都相同,不过它们之间仍然有以下区别。
(1)GET请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器 。当然 ,在Ajax请求中,这种区别对用户是不可见的。
(2)GET方式对传输的数据有大小限制(通常不能大于2KB ),而使用POST方式传递的数据量要比GET方式大得多(理论上不受限制)。
(3)GET方式请求的数据会被浏览器缓存起来,因此其他人就可以从浏览器的历史记录中读取到这些数据,例如账号和密码等。在某种情况下,GET方式会带来严重的安全性问题,而POST方式相对来说就可以避免这些问题。
(4)GET方式和POST方式传递的数据在服务器端的获取也不相同 。 在 PHP中 , GET方式的数据可以用$_GET[]获取,而POST方式可以用$_POST[]获取。两种方式都可以用$_REQUEST[]来获取。
由于 POST 和 GET 方式提交的所有数据都可以通过 $_REQUEST[] 来获取,因此只需要改变 jQuery 函数,就可以将程序在 GET 请求和 POST 请求之间切换。代码如下:
<script language="javascript" > $(function(){ $("#send").click(function(){ $.post("post1.jsp", { username : $("#username").val() , content : $("#content").val() }, function (data, textStatus){ $("#resText").html(data); // 把返回的数据添加到页面上 } ); }) }) </script>
另外,当 load() 方法带有参数传递时 , 会使用 POST 方式发送请求。因此也可以使用 load() 方法来完成同样的功能。
上面使用 load()、$.get() 和 $.post() 方法完成了一些常规的 Ajax 程序,如果还需要编写一些复杂的 Ajax 程序,那么就要用到 jQuery 中的 $.ajax() 方法。 $.ajax() 方法不仅能实现与 load()、$.get() 和 $.post() 方法同样的功能,而且还可以设定 beforeSend (提交前回调函数 )、error (请求失败后处理)、success (请求成功后处理)以及 complete (请求完成后处理)回调函数,通过这些回调函数,可以给用户更多的 Ajax 提示信息。另外,还有一些参数,可以设置 Ajax 请求的超时时间或者页面的"最后更改"状态等。关于$.ajax() 方法将在后面进行讲解。
$.getScript() 方法和 $.getJson() 方法
$.getScript()
有时候,在页面初次加载时就取得所需的全部 JavaScript 文件是完全没有必要的。虽然可以在需要哪个 JavaScript 文件时,动态地创建<script>标签,jQuery 代码如下:
$(document.createElement("script")).attr("src", "test.js").appendTo("head");
或者
$("<script type='text/javascript' src='test.js'/>").appendTo("head");
但这种方式并不理想。为此, jQuery 提供了 $.getScript() 方法来直接加载 .js 文件,与加载一个 HTML 片段一样简单方便,并且不需要对 JavaScript 文件进行处理, JavaScript 文件会自动执行。
jQuery 代码如下:
<script> $(function(){ $('#send').click(function() { $.getScript('test.js'); }); }) </script>
test.js文件内容如下
var comments = [ { "username": "张三", "content": "沙发." }, { "username": "李四", "content": "板凳." }, { "username": "王五", "content": "地板." } ]; var html = ''; $.each( comments , function(commentIndex, comment) { html += '<div class="comment"><h6>' + comment['username'] + ':</h6><p class="para">' + comment['content'] + '</p></div>'; }) $('#resText').html(html);
当"加载"按钮被单击后,出现如下图所示的效果。
与其他 Ajax 方法一样,$.getScript() 方法也有回调函数,它会在 JavaScript 文件成功载入后运行。例如想载入 jQuery 官方颜色动画插件( jquery.color.js ),成功后给元素绑定颜色变化动画,就可以用到 $.getScript() 方法的回调函数。代码如下:
<script> $(function(){ $.getScript('jquery.color.js',function(){ $("<p>加载JavaScript完毕</p>").appendTo("body"); $("#go").click(function(){ $(".block").animate( { backgroundColor: 'pink' }, 1000) .animate( { backgroundColor: 'blue' }, 1000); }); }); }) </script> <body> <button id="go">运行</button> <div class="block"></div> </body>
当 jquery.color.js 动画插件加载完毕后,单击 id 为"go"按钮时, class 为 block 的元素就有了颜色动画变化。
$.getJSON()
$.getJSON() 方法用于加载 JSON 文件,与 $.getScript() 方法的用法相同。
jQuery 代码如下:
<script> $(function(){ $('#send').click(function() { $.getJSON('test.json', function(data) { $('#resText').empty(); var html = ''; $.each( data , function(commentIndex, comment) { html += '<div class="comment"><h6>' + comment['username'] + ':</h6><p class="para">' + comment['content'] + '</p></div>'; }) $('#resText').html(html); }) }) }) </script> <body> <p> <input type="button" id="send" value="加载"/> </p> <div class="comment">已有评论:</div> <div id="resText"></div> </body>
可以在函数中通过 data 变量来遍历相应的数据,也可以使用迭代方式为每个项构建相应的HTML代码。虽然在这里可以使用传统的 for 循环来实现,但既然是讲解 jQuery,那么还是使用jQuery 里的方法。 jQuery 提供了一个通用的遍历方法 $.each(),可以用于遍历对象和数组。
$.each() 函数不同于 jQuery 对象的 each() 方法,它是一个全局函数,不操作 jQuery 对象,而是以一个数组或者对象作为第1个参数,以一个回调函数作为第2个参数。回调函数拥有两个参数:第1个为对象的成员或数组的索引,第2个为对应变量或内容。代码如下:
在上面的代码中,当返回数据成功后,首先清空 id 为 "resText" 的元素的内容,以便重新构造新的 HTML,然后通过 $.each() 循环函数依次遍历每个项,并将遍历出来的内容构建成 HTML 代码拼接起来,最后将构建好的 HTML 添加到 id 为 "resText" 的元素中。
当"加载"按钮被单击后,出现如下图所示的效果。
不仅如此,还能通过使用 JSONP 形式的回调函数来加载其他网站的 JSON 数据(此案例未实现效果),例如从图片网站( http://Flickr.com )搜索汽车类别的4张最新图片。代码如下:
<script> $(function(){ $('#send').click(function() { $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=car&tagmode=any&format=json&jsoncallback=?", function(data){ $.each(data.items, function( i,item ){ $("<img class='para'/> ").attr("src", item.media.m ).appendTo("#resText"); if ( i == 3 ) { return false; } }); } ); }) }) </script> <body> <p> <input type="button" id="send" value="加载"/> </p> <div id="resText"></div> </body>
上面的代码中再次用到全局函数 $.each() 来遍历数据,因为只需要4张图片,所以当 i =3的时候就需要退出循环。在 $.each() 函数中,如果需要退出 each 循环,只要返回 false 即可。
当"加载"按钮被单击后,从 Flickr 网站加载的4张最新的汽车图片就会被添加到页面中。
注意:
(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 等。