一、jQuery的Ajax方法
jQuery对Ajax 做了大量的封装,使用起来也较为方便,不需要去考虑浏览器兼容性。对于封装的方式,jQuery 采用了三层封装:
- 最底层的封装方法为——$.ajax()
- 而通过这层封装了第二层有三种方法——.load()、$.get()和$.post()
- 最高层是——$.getScript()和$.getJSON()方法
1.1 .load()方法 —— 载入远程 HTML 文件代码并插入至 DOM 中
load(url, [data], [callback])
- load是局部方法,需要一个包含元素的jQuery 对象作为前缀,对于用途而言,.load()适合做静态文件的异步获取
- url:待装入 HTML 网页网址。
- data:发送至服务器的 key/value 数据。在jQuery 1.3中也可以接受一个字符串了。向服务器提交数据有两种方式:get 和post。
//不传递data,则默认get 方式,data使用?方式 $('input').click(function () { $('#box').load('test.php?url=ycku'); }); //传递data,则为post 方式,data必须使用键值对方式 $('input').click(function () { $('#box').load('test.php', { url : 'ycku' }); });
- callback:载入成功时回调函数,其参数如下图
回调函数callback也可以传递三个可选参数:
- responseText(请求返回):
- status(请求状态): 如果成功返回数据则为:success,否则为:error
- XMLHttpRequest(XMLHttpRequest 对象):否则为:error
$('input').click(function () { $('#box').load('test.php', { url : 'ycku' }, function (response, status, xhr) { alert('返回的值为:' + response + ',状态为:' + status + ',状态是:' + xhr.statusText); }); });
1.2 $.get()和$.post()
jQuery.get(url, [data], [callback], [type])
jQuery.post(url, [data], [callback], [type])
- $.get()和$.post()是全局方法,无须指定某个元素。对于用途而言,.load()适合做静态文件的异步获取,
而对于需要传递参数到服务器页面的,$.get()和$.post()更加合适 - url:发送请求地址。
- data:待发送 Key/value参数
//通过直接在url问号紧跟传参 $('input').click(function () { $.get('test.php', 'url=ycku',function (response, status, xhr) { $('#box').html(response); }); }); //通过第二个参数data,字符串形式的键值对传参,然后自动转换为问号紧跟传参 $('input').click(function () { $.get('test.php', { url : 'ycku' },function (response, status, xhr) { $('#box').html(response); }); }); //通过第二个参数data,对象形式的键值对传参,然后自动转换为问号紧跟传参 $('input').click(function () { $.post('test.php?url=ycku', function (response, status, xhr) { $('#box').html(response); }); }); //post提交不能使用问号传参 $('input').click(function () { $.post('test.php', 'url=ycku',function (response, status, xhr) { $('#box').html(response); }); }); //post提交可以使用字符串形式的键值对传参,自动转换为http消息实体传参 $('input').click(function () { $.post('test.php', { url : 'ycku' },function (response, status, xhr) { $('#box').html(response); }); }); //post提交可以使用对象键值对 $('input').click(function () { $.post('test.php', { url : 'ycku' },function (response, status, xhr) { $('#box').html(response); }, 'html'); //PHP文件返回的数据是纯文本,默认是html或text });
- callback:发送成功时回调函数。
- type:返回内容格式,xml, html, script, json, text, _default,。一般情况下type 参数是智能判断,并不
需要我们主动设置,如果主动设置,则会强行按照指定类型格式返回。
//使用$.get()异步返回html 类型 $('input').click(function () { $.get('test.php', { url : 'ycku' }, function (response,status, xhr) { if (status == 'success') { $('#box').html(response); } }) //type 自动转为html });
//本身是纯文本,如果强行按照xml或者json数据格式返回的话,那么就无法获取数据 $('input').click(function () { $.post('test.xml',function (response, status, xhr) { alert(response); }, 'html'); //默认type就已经是xml }); //如果默认已经是xml,强行设置为html,则会连xml标签也返回 $('input').click(function () { $.post('test.xml',function (response, status, xhr) { alert($(response).find('root').find('url').text()); }); });
$.post()方法的使用和$.get()基本上一致,他们之间的区别也比较隐晦,基本都是背后的不同,在用户使用上体现不出。具体区别如下:
- .GET请求是通过URL提交的,而POST 请求则是HTTP消息实体提交的;
- .GET提交有大小限制(2KB),而POST 方式不受限制;
- .GET方式会被缓存下来,可能有安全性问题,而POST没有这个问题;
- .GET方式通过$_GET[]获取,POST 方式通过$_POST[]获取。
1.3 $.getScript()和$.getJSON()
jQuery 提供了一组用于特定异步加载的方法:
- $.getScript()——能够特定的情况再加载JS 文件,而不是一开始把所有JS 文件都加载了
- $.getJSON()——用于专门加载JSON 文件
//点击按钮后再加载JS 文件 $('input').click(function () { $.getScript('test.js'); }); //$.getJSON()方法是专门用于加载JSON 文件的,使用方法和之前的类似 $('input').click(function () { $.getJSON('test.json', function (response, status, xhr) { alert(response[0].url); }); });
1.4 .$.ajax()
jQuery.ajax(url,[settings])
- $.ajax()是所有ajax 方法中最底层的方法,所有其他方法都是基于$.ajax()方法的封装。
- 最简单的情况下,$.ajax()可以不带任何参数直接使用。
注意,所有的选项都可以通过$.ajaxSetup()函数来全局设置
$('form input[type=button]').click(function () { $.ajaxSetup({ type : 'POST', url : 'test.php', data : $('form').serialize() }); $.ajax({ success : function (response, status, xhr) { alert(response); } }); });
//$.ajax 使用 $('input').click(function () { $.ajax({ type : 'POST', //这里可以换成GET url : 'test.php', data : { url : 'ycku' }, success : function (response, stutas, xhr) { $('#box').html(response); } }); });
$.ajax({ type : 'POST', url : 'user.php', data : $('form').serialize(), success : function (response, status, xhr) { alert('请求成功后'); }, complete : function () { alert('请求完成后,不管是否失败成功'); }, beforeSend : function () { alert('发送请求之前执行'); }, error : function () { alert('请求失败后'); } });
1.5 表单序列化.serialize(),.serializeArray()
- .serialize()
- .serializeArray() —— 返回JSON 数据的方法
//使用.serialize()序列化表单内容 $('form input[type=button]').click(function () { $.ajax({ type : 'POST', url : 'test.php', data : $('form').serialize(), success : function (response, status, xhr) { alert(response); } }); });
1.6 jQuery.param(obj,[traditional])——将表单元素数组或者对象序列化。是.serialize()的核心方法
var myObject = { a: { one: 1, two: 2, three: 3 }, b: [1,2,3] }; var recursiveEncoded = $.param(myObject); var recursiveDecoded = decodeURIComponent($.param(myObject)); alert(recursiveEncoded); //a%5Bone%5D=1&a%5Btwo%5D=2&a%5Bthree%5D=3&b%5B%5D=1&b%5B%5D=2&b%5B%5D=3 alert(recursiveDecoded); //a[one]=1&a[two]=2&a[three]=3&b[]=1&b[]=2&b[]=3 var shallowEncoded = $.param(myObject, true); //a=%5Bobject+Object%5D&b=1&b=2&b=3 var shallowDecoded = decodeURIComponent(shallowEncoded); //a=[object+Object]&b=1&b=2&b=3
注意: 因为有时程序对于复杂的序列化解析能力有限,serialize()虽然encode字符,但使用$.param()将对象形式的键值对转为URL 地址的字符串键值对,可以更加稳定准确的传递表单内容。
二、请求全局事件方法
- 全局事件——每次Ajax请求都会触发,它会向DOM中的所有元素广播
jQuery新版本规定请求全局事件方法是所有Ajax请求都会触发到,并且只能绑定在document元素上(若绑定多次,则会依次触发为事件注册的回调函数),而局部方法,只针对某个Ajax请求
//$.post()使用局部方法.success() $.post('test.php', $('form').serialize(), function (response, status, xhr) { $('#box').html(response); }).success(function (response, status, xhr) { alert(response); }); //$.post()使用全局事件方法.ajaxSuccess() $(document).ajaxSuccess(function (event, xhr, settings) { alert(xhr.responseText); });
ajaxStart |
开始新的Ajax请求,并且此时jQuery对象上没有其他ajax请求正在进行。 签名:function(e) 函数说明:传入事件对象 |
ajaxSend |
当一个Ajax请求开始时触发 签名:function(e,jqXHR,s) 函数说明:传入事件对象、jqXHR、s对象 |
ajaxSuccess |
全局的请求成功 签名:function(e,jqXHR,s,data) 函数说明:传入事件对象、jqXHR、s对象、请求成功返回的相应数据 |
ajaxError |
全局的发生错误时触发 签名:function(e,jqXHR,s,errorData) 函数说明:传入事件对象、jqXHR、s对象、请求失败返回的错误信息 |
ajaxComplete |
全局的请求完成时触发 签名:function(e,jqXHR,s) 函数说明:传入事件对象、jqXHR、s对象 |
ajaxStop |
当jQuery对象上正在进行Ajax请求都结束时触发。 签名:function(e) 函数说明:传入事件对象 |
. 如果某个ajax不想触发全局事件,可以设置取消
$.ajax({global : false});
. 如果请求时间太长,可以设置超时
$.ajax({timeout : 500});
- .ajaxStart()、.ajaxStop()——加载请求
请求加载提示的显示和隐藏
$(document).ajaxStart(function () { $('.loading').show(); }).ajaxStop(function () { $('.loading').hide(); });
- .ajaxError(),参见后面
- .ajaxSuccess(),对应一个局部方法:.success(),请求成功时候调用
- .ajaxComplete(),对应一个局部方法:.complete(),请求完成后调用
- .ajaxSend(),没有局部方法,只有属性beforeSend,请求发生之前要绑定的函数
// 全局事件 $("#div_event").ajaxStart(function (e) { doAddEvent4textarea('txt_event', '触发ajaxStart回调函数'); }); $("#div_event").ajaxSend(function (e) { doAddEvent4textarea('txt_event', '触发ajaxSend回调函数'); }); $("#div_event").ajaxSuccess(function (e, jqXHR, s, data) { doAddEvent4textarea('txt_event', '触发ajaxSuccess回调函数'); }); $("#div_event").ajaxError(function (e, jqXHR, s, errorData) { doAddEvent4textarea('txt_event', '触发ajaxError回调函数'); }); $("#div_event").ajaxComplete(function (e, jqXHR, s) { doAddEvent4textarea('txt_event', '触发ajaxComplete回调函数'); }); $("#div_event").ajaxStop(function (e) { doAddEvent4textarea('txt_event', '触发ajaxStop回调函数'); }); // 局部事件 function bindLocalEvent(e) { var textareaid = e.data.textareaid; var global = e.data.global; $.ajax('AjaxHandler.ashx?func=btn_nowTime_long', { type: 'get', dataType: 'text', global: global, cache: false, beforeSend: function (jqXHR, s) { doAddEvent4textarea(textareaid, '触发beforeSend回调函数'); }, dataFilter: function (data, dataType) { doAddEvent4textarea(textareaid, '触发dataFilter回调函数'); }, success: function (data, statusText, jqXHR) { doAddEvent4textarea(textareaid, '触发success回调函数'); }, error: function (jqXHR, textStatus, errorThrown) { doAddEvent4textarea(textareaid, '触发error回调函数'); }, complete: function (jqXHR, textStatus) { doAddEvent4textarea(textareaid, '触发complete回调函数'); } }); } function doAddEvent4textarea(textareaid, txt) { var textarea = $("#" + textareaid); textarea.val(textarea.val() + '\r\n' + txt); }
三、错误处理
- jQuery1.5之前$.get()、$.post()、.load()方法通过全局.ajaxError()事件方法来返回错误信息
- jQuery1.5之后,通过连缀处理局部.error()方法
- $.ajax()可以用以上两个方法,也可以使用自己的属性方法error : function () {}
//$.ajax()使用属性提示错误 $.ajax({ type : 'POST', url : 'test1.php', data : $('form').serialize(), success : function (response, status, xhr) { $('#box').html(response); }, error : function (xhr, errorText, errorStatus) { alert(xhr.status + ':' + xhr.statusText); } }); //$.post()使用.error()方法提示错误,该方法将被fail()替代 $.post('test1.php').error(function (xhr, status, info) { alert(xhr.status + ':' +xhr.statusText); alert(status + ':' + info); }); //$.post()使用全局.ajaxError()事件提示错误 $(document).ajaxError(function (event, xhr, settings, infoError) { alert(xhr.status + ':' +xhr.statusText); alert(settings+ ':' + info); });
四、跨域操作——JSON和JSONP
在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略——所谓同源是指,域名host,协议protocol,端口port相同)。这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容。
4.1 $.ajax()跨域原理分析
由于javascript的安全限制“同源策略”,所以我们无法使用XMLHttpRequest直接请求别的域名下的资源。不过拥有src属性和href属性的<script>\<img>\<iframe>和<link>\<a>标签不受同源策略影响。$.ajax()提供的两种解决方案正是应用了动态创建<script>的方式来实现(即:生成<script>标签,src引入脚本,然后执行,最后移除<script>标签)。
4.2 跨域解决方法
① JSONP(JSON with padding)是一个非官方的协议,它容许在服务器端集成Script tags返回客户端,通过javascript callback的形式实现跨域访问。如果想跨域调用文件,必须使用JSONP。
② callback方法
//跨域的PHP端 <?php $arr = array('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5); $result = json_encode($arr); $callback = $_GET['callback']; echo $callback."($result)"; ?>
//$.getJSON()方法跨域获取JSON,使用?callback=?方法 $.getJSON('http://www.li.cc/test.php?callback=?', function (response) { console.log(response); }); //$.ajax()方法跨域获取JSON,使用?callback=?方法 $.ajax({ url : 'http://www.li.cc/test.php?callback=?', dataType : 'json', success : function (response, status, xhr) { console.log(response); alert(response.a); } }); //$.ajax()获取远程数据,使用jsonp方法 $.ajax({ type : 'POST', url : 'http://www.li.cc/jsonp2.php', dataType : 'jsonp', success : function (response, status, xhr) { console.log(response); ert(response.a); } });
说明;
- 不会触发全局事件和局部事件;只支持GET方式(POST请求会自动转化为GET请求);默认不启用缓存(cache:false)
- jsonp方式可以通过jsonp和jsonpCallback参数指定一个特定回调函数
五、jqXHR对象
jQuery定义了一个jqXHR对象,它是原生对象XHR的一个超集(为不同浏览器内置的XMLHttpRequest提供了一致的超集),jqXHR对象我们常常使用如下成员,这些成员主要用于ajax的全局事件和局部事件,并且做为$.ajax()函数返回值返回。
jqXHR:{ readyState ,setRequestHeader: function( name, value ) ,getAllResponseHeaders: function() ,getResponseHeader: function( key ) ,overrideMimeType: function( type ) ,abort: function( statusText ) ,responseText ,responseXML }
jqXHR的全部成员如下
var jqXHR = $.ajax({ type : 'POST', url : 'test.php', data : $('form').serialize() }); for (var i in jqXHR) { document.write(i + '<br />'); }
建议用jqXHR 的.done()、.always()、.fail()来代替.success()、.complete()、.error()。未来版本中,这三种方法可能被废弃取消
jqXHR.done(function (response) { $('#box').html(response); });
使用jqXHR的连缀方式比$.ajax()的属性方式有三大优点:
- 可以连缀操作,可读性大大提高
- 可以多次执行同一个回调函数
- 可以为多个操作指定回调函数
//$.ajax多个成功后,提交的是第二个(最后一个) $.ajax({ type : 'POST', url : 'user.php', data : $('form').serialize() success: function(response,status,xhr){ alert(response+"1"); }, success: function(response,status,xhr){ alert(response+"2"); } }); //jqXHR可以同时执行多个成功后的回调函数 jqXHR.done().done(); //多个操作指定同回调函数 var jqXHR = $.ajax('test.php'); var jqXHR2 = $.ajax('test2.php'); $.when(jqXHR, jqXHR2).done(function (r1,r2) { alert(r1[0]); alert(r2[0]); });