内容很繁杂,长话短说。关于Ajax的介绍在这儿。
导读
jQuery 对 Ajax 做了大量的封装,我们使用起来也较为方便,不需要去考虑浏览器兼容性。对于封装的方式,jQuery 采用了三层封装:最底层的封装方法为:$.ajax()
,而通过这层封装了第二层有三种方法:.load()
、$.get()
和$.post()
,最高层是$.getScript()
和$.getJSON()
方法。
load()
$element.load( url [, data ] [, complete ] )。data可以是 “String” 或 “Object” 。load()是以post方式请求的。
$( 'body' ).load( 'abc.php .selector' );
$( 'body' ).load( 'abc.php?name=real&age=20' );
$( 'body' ).load( 'abc.php', 'name=real&age=20' );
$( 'body' ).load( 'abc.php', { name:'real', age:20 } );
$( 'body' ).load( 'abc.php', { name:'real', age:20 }, function ( data ) {} );
get()和post()
$.get( url [, data ] [, success ] [, dataType ] )
$.post( url [, data ] [, success ] [, dataType ] )
第四参数 type 是指定异步返回的类型。一般情况下 type 参数是智能判断,并不
需要我们主动设置,如果主动设置,则会强行按照指定类型格式返回。
如果载入的是 xml 文件,type 会智能判断。如果强行设置 html 类型返回,则会
把 xml 文件当成普通数据全部返回,而不会按照 xml 格式解析数据。
关于get和post的区别这里就不说了。在这里写过。
getScript()和getJSON()
$.getScript( url [, success ] )
$.getJSON( url [, data ] [, success ] )
jQuery 提供了一组用于特定异步加载的方法:$.getScript()
,用于加载特定的 JS 文件;
$.getJSON()
,用于专门加载 JSON 文件。
有时我们希望能够特定的情况再加载 JS 文件,而不是一开始把所有 JS 文件都加载了,
这时可以使用$.getScript()方法。
ajax()
$.ajaxSetup( options )
有时,我们可能会在同一个程序中多次调用$.ajax()
方法。而它们很多参数都相同,这个时候我们课时使用 jQuery 提供的$.ajaxSetup()请求默认值来初始化参数。即使设置了$.ajaxSetup
,但它仍可以被$.ajax
覆盖。
$.ajaxSetup({
type : 'POST'
});
$.ajax( url [, settings ] )
$.ajax( [settings ] )
(常用)
$.ajax()
是所有 ajax 方法中最底层的方法,所有其他方法都是基于$.ajax()方法的封装。
与上述方法不同的是,上述基于ajax封装的方法并没有提供错误回调函数。更具体的在[jQuery官方api]。(http://api.jquery.com/jQuery.ajax/)
$.ajaxStart( function () {
$( '.loading' ).show();
})
$.ajaxStop( function () {
$( '.loading' ).hide();
})
$.ajax({
type: 'get',
url: 'some.php',
data: $('#someForm').serizlize(),
success: function ( data ) {}
timeout: 15000,
error: function ( data ) {}
})
序列化
对于表单,我们更喜欢直接用序列化来发送数据。因为这样很方便。
.serialize()方法不但可以序列化表单内的元素,还可以直接获取单选框、复选框和下拉
列表框等内容。
除了.serialize()方法,还有一个可以返回 JSON 数据的方法:.serializeArray()。这个方法
可以直接把数据整合成键值对的 JSON 对象。
在使用 data 属性传递的时候,如果是以对象形式传递键值对,可以使用$.param()方法将对象转换为字符串键值对格式。使用$.param()
将对象形式的键值对转为 URL 地址的字符串键值对,可以更加稳定准确的传递表单内容。因为有时程序对于复杂的序列化解析能力有限,所以直接传递 obj对象要谨慎。
比如console.log($.param({a:1,b:2}));// a=1&b=2
如下是一张序列化的表单数据:
<body>
<form action="">
账户名:<input type="text" name="username"/>
密码:<input type="password" name="password"/>
电子邮箱: <input type="email" name="email"/>
性别:
<input type="radio" name="sex" value="male"/>男
<input type="radio" name="sex" value="female"/>女
爱好:
<input type="checkbox" name="basketball" value="basketbal"/>篮球
<input type="checkbox" name="football" value="football"/>足球
省份:
<select name="province" id="">
<option value="0">安徽</option>
<option value="1">重庆</option>
<option value="2">四川</option>
</select>
<button>提交</button>
</form>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
$('button').click( function( e ) {
e.preventDefault();
console.log($('form').serialize());
console.log($('form').serializeArray());
})
</script>
</body>
上面是直接序列化,下面是序列化为数组。前者是String类型,后者是Object类型
全局事件
在ajax请求中有个global属性,默认是true,表示可以使用全局事件,如果设置为false,那么下列这些函数将对这个ajax请求不起作用。
$( document ).ajaxStart( handler )
:请求开始执行。
$( document ).ajaxStop( handler )
:请求结束执行。
$( document ).ajaxSend( handler )
:在Ajax请求发送前执行。
$( document ).ajaxError( handler )
:请求出错执行。
$( document ).ajaxSuccess( handler )
:请求成功,对数据处理后执行。
$( document ).ajaxComplete( handler )
:请求完成 执行,不管成功失败。
这些全局事件与$.ajax
中的事件是一样的,不过它是针对所有ajax请求的。
以上代码在 jQuery1.8 及以后的版本不在有效,需要使用 jquery-migrate 向下兼容才能运行。新版本中,必须绑定在 document 元素上。
jsonp
关于jsonp,在这里已经讲得很清楚了。这次主要讲jQuery中的jsonp。原理都一样,表现形式不同而已。
简单得说,对于一个ajax请求,如果涉及到跨域操作,那么浏览器肯定会报错。除非服务器端设置了头部信息"Access-Control-Allow-Origin:*"
。如果在ajax请求中加上dataType:"jsonp"
,并且在url后面加上一个参数callback=?
(请求的是纯数据,不是callback(data)
的形式)。jQuery会将”?”替换为它自己定义的函数名,这个函数名与success的函数名是一样的。并将请求到的数据作为data参数传入success函数。对于一些接口来说,可能返回的就是callback(data)
的形式,那么我们就要根据接口来指定回调函数。比如百度搜索的接口就是使用的cb=?
cb参数作为回调。而不再是callback。
$.ajax({
type:'get',
url:'http://suggestion.baidu.com/su?wd=d&p=3&cb=?',
dataType:'jsonp',
success:function (data){
console.log(data);
},
error:function(){
alert('error')
}
})
jqXHR
jQuery中所有的ajax方法都会返回jqXHR对象。只要把这个对象保存起来,随后就可以方便地使用这些属性和方法。
在上面的关于$.ajax
参数设置的时候,有success、error、complete回调函数。如果使用jqXHR对象的话,可以使用.done()、.error()、.always()来代替。
jqXHR.done(function( data, textStatus, jqXHR ) {});
jqXHR.fail(function( jqXHR, textStatus, errorThrown ) {});
jqXHR.always(function( data|jqXHR, textStatus, jqXHR|errorThrown ) { });
使用 jqXHR 的连缀方式比$.ajax()的属性方式有三大好处:
- 可连缀操作,可读性大大提高;
可以多次执行同一个回调函数;
jqXHR.done(response).done(response);
- 为多个操作指定回调函数;
$.when(jqXHR, jqXHR2).done(function (r1,r2) {
alert(r1[0]);
alert(r2[0]);
});
缓存相应
如果想重复使用同一段数据,那么重复发送Ajax请求显示是一种浪费。为了编码这样做,我可以吧返回的jqXHR缓存在一个对象中。在需要使用这些数据时,可以先去这个对象寻找。如果有,就直接使用,如果没有,则需要发送Ajax请求,再将返回的jqXHR缓存起来。
<form>
<input type="text" placeholder="请输入搜索内容"/>
<button>提交</button>
</form>
var jqXHRs = {};
$( 'form' ).submit( function ( e ) {
e.preventDefault();
var search = $( 'input' ).val();
if ( !jqXHRS[search] ) {
jqXHRS[search] = $.ajax({
url: 'someURL',
dataType: 'jsonp',
data: 'title=' + search,
timeout: 15000
})
}
jqXHRS[search].done( successHandle ).fail( failHandle ).always( completeHandle );
})
通过这种方法,就可以消除重复的请求。
截流Ajax请求
实现搜索功能时,越来越常见的是在用户输入过程动态地列出搜索结果来。通过给keyup事件绑定一个处理程序,来实现实时搜索功能。
在缓存响应部分,我们已经节省了一些请求了。不过,通过截流请求,还可以进一步减少服务器的负担。
var
searchTimeout = null,
searchDelay = 300
;
$( '#title' ).keyup( function () {
clearTimeout( searchTimeout );
searchTimeout = setTimeout( function () {
$( 'form' ).trigger( 'submit' );
},searchDelay)
})
在用户第一次松开键时设置一个定时器,之后每次松开都会重置定时器并设置一个新的定时器。只有用户停止击键后超过预定的300毫秒后,才会触发 “submit” 事件。
数据类型转换器
要定义一种新的数据类型,需要给$.ajaxSetup
传递三个参数:accepts、contents和converters。其中,accepts属性会添加发送到服务器的头部信息,声明我们的脚本可以理解的特定的MIME类型;contents属性处理数据交换的另一方,它提供一个与相应的MIME类型进行匹配的正则表达式,以尝试自动检测这个元数据当中的数据类型。最后converters中包含解析返回数据的函数。
$.ajaxSetup({
accepts: {
yaml: 'application/x-yaml, text/yaml'
},
contents: {
yaml: /yaml/,
},
converters: {
'text yaml': function ( textValue ) {
console.log( textValue );
return;
}
}
})
$.ajax({
url: 'categories.yml',
dataType: 'yaml'
})
上述代码中,$.ajax()
读取了一个YAML文件并把数据类型声明为yaml。因为到来的数据会按照text格式解析,jQuery需要一种机制能把一种数据类型转换为另一种数据类型。converters的’text yaml’告诉jQuery,这个转换函数以text格式接收数据,然后以yaml格式解析。
在转换函数内部,我们只是把文本内容记录到控制台中,以便验证这个函数能够被正确调用。要实现实际地转换,需要加载第三方的YAML解析库(yaml.js)并调用其方法。
ajaxPrefilter
$.ajaxPrefilter( [dataTypes ], handler )
所谓预过滤器,就是一些回调函数,他们可以在发送请求前对请求进行过滤。预过滤器会在$.ajax()
修改或在使用它的任何选项之前调用,因此通过预过滤器可以修改这些选项或基于新的、自定义选项发送请求。
一个典型的预处理器如下:
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
// Modify options, control originalOptions, store jqXHR, etc
});
- options:ajax请求对象(setting)。
- originalOptions:作为一个默认options提供给
$.ajax()
。类似于$.ajaxSetup。我的测试结果是,如果originalOptions和$.ajaxSetup
有相同的键,那么值以$.ajaxSetup为准
。 - jqXHR:请求返回的jqXHR对象。
修改options
var currentRequests = {};
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
if ( options.abortOnRetry ) {
if ( currentRequests[ options.url ] ) {
currentRequests[ options.url ].abort();
}
currentRequests[ options.url ] = jqXHR;
}
});
如果ajax请求相同的url并且options.abortOnRetry设置为true,那么这个请求会被abort()。
$.ajaxPrefilter(function( options ) {
if ( options.crossDomain ) {
options.url = "http://mydomain.net/proxy/" + encodeURIComponent( options.url );
options.crossDomain = false;
}
});
如果是跨域请求,添加上域名。
过滤特定的dataType
$.ajaxPrefilter( "json script", function( options, originalOptions, jqXHR ) {
// Modify options, control originalOptions, store jqXHR, etc
});
如果设置了第一个参数dataType,那么预过滤器只会验证dataType定义的数据类型。比如上述只验证dataType是json或者script的请求。
自定义dataType
$.ajaxPrefilter(function( options ) {
if ( isActuallyScript( options.url ) ) {
return "script";
}
});
检测options.url,如果是script类型,那么就设置它的dataType为script。
$.ajaxTransport
transport是最高级的一种增强ajax的方法。当数据类型转换器和预过滤器都无法解决时可以采用它。
$.ajaxTransport( dataType, handler )
handler: function( options, originalOptions, jqXHR )
。这三个参数在预过滤器已经说过。
handler函数返回一个带有.send()和.abort()方法的对象。其中.send()方法负责发送请求,处理相应并把数据发送给回调函数。而.abort()方法会立即停止请求。
$.ajaxTransport( dataType, function( options, originalOptions, jqXHR ) {
if( /* transportCanHandleRequest */ ) {
return {
send: function( headers, completeCallback ) {
// Send code
},
abort: function() {
// Abort code
}
};
}
});
headers: 是一个键值对的请求头对象,如果transport支持它,就会传送它
。
complete: function( status, statusText, responses, headers ) {}
。
response:一个键值对对象。键是transport能够支持的dataType,值是返回给 success回调函数/done中的回调函数 的data。
具体的在jquery api。
下面给出具体代码使ajax能够解析图像文件。
<script type="text/javascript">
$.ajaxTransport( 'img', function ( settings ) {
var $img, img, prop;
return {
send: function ( headers, complete ) {
$img = $( '<img>', {
src: settings.url
});
img = $img[0];
prop = typeof img.naturalWidth ? 'width' : 'naturalWidth';
if ( img.complete ) {
callback( !!img[prop] );
} else {
$img.on( 'load error', function ( event ) {
callback( event.type == 'load' );
})
}
function callback( success ) {
if ( success ) {
complete( 200, 'OK', { img: img });
} else {
$img.remove();
complete( 404, ' Not Found ');
}
}
},
abort: function () {
if ( $img ) {
$img.remove();
}
}
}
})
$( document ).ready( function () {
$.ajax({
url: 'img/HBuilder.png',
dataType: 'img'
}).done( function ( img ) {
$('<div></div>', {
id: 'picture',
html: img
}).appendTo( 'body' );
}).fail( function (xhr, textStatus, msg) {
$( '<div></div>', {
id: 'picture',
html: textStatus + ':' + msg
}).appendTo( 'body' );
})
})
</script>
本来ajax是不支持图像文件的,但是经过ajaxTransport后,就可以支持图像文件了。
小结
1,基础:从load讲起,依次有get、post、getJSON、getScript、ajax
2,增强:jsonp、全局函数、jqXHR
3,高级:缓存相应,截流、数据类型转换、预过滤器、替代传输机制。
4,工具函数:serialize、serializeArray、$.param
5,既然选择了程序员这条路,那就走下去。
参考
jQuery基础教程(第四版)
李炎恢jQuery视频讲义