用ajax的局部刷新來給網(wǎng)站提升用戶體驗(yàn)我們已經(jīng)用過很多了,ajax已然成為了前端開發(fā)最重要的“工具”之一。
但是,我想應(yīng)該會(huì)有不少人在使用ajax的時(shí)候都在依賴于jQuery或者prototype或者其他js庫(kù)。但現(xiàn)實(shí)是,假設(shè)某一天一個(gè)項(xiàng)目不能引入任何一個(gè)js庫(kù),只能用原生js寫代碼,那你怎么辦?又或者是一個(gè)非常簡(jiǎn)單的頁(yè)面,但是要用到ajax,難道就為了下這么一個(gè)ajax請(qǐng)求要引用一個(gè)jq這么大的js庫(kù)?我想這是不值得的,所以我們應(yīng)該學(xué)會(huì)用原生的js來寫ajax,并且把它封裝好以便于以后使用。
由于之前使用過jq的ajax而且覺得他使用起來挺舒服的,所以我在封裝ajax的時(shí)候一方面舍去了很多不常用的參數(shù)只留下了最常用的幾個(gè)功能,另一方面盡量保持它原有的使用風(fēng)格。
我一共只留了五個(gè)參數(shù),他們分別是發(fā)送方式(type)、發(fā)請(qǐng)求的url(url)、是否為異步請(qǐng)求(async)、發(fā)送的參數(shù)(data)、傳輸成功的回調(diào)函數(shù)(success),函數(shù)代碼如下:
/* 封裝ajax函數(shù)
* @param {string}opt.type http連接的方式,包括POST和GET兩種方式,默認(rèn)使用GET
* @param {string}opt.url 發(fā)送請(qǐng)求的url
* @param {boolean}opt.async 是否為異步請(qǐng)求,true為異步的,false為同步的
* @param {object}opt.data 發(fā)送的參數(shù),格式為對(duì)象類型
* @param {function}opt.success ajax發(fā)送并接收成功調(diào)用的回調(diào)函數(shù)
*/
function ajax(opt) {
opt = opt || {};
var method = opt.method || 'GET';
method = method.toUpperCase() || 'GET';
var url = opt.url || '';
var async = opt.async || true;
var data = opt.data || null;
var success = opt.success || function () {};
var xmlHttp = null;
if (XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
else {
xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
}
var params = [];
for (var key in data){
params.push(key + '=' + data[key]);
}
var dataStr = params.join('&');
if (method === 'POST') {
xmlHttp.open(method, url, async);
xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
xmlHttp.send(dataStr);
}
else {
xmlHttp.open(method, url + '?' + dataStr, async);
xmlHttp.send(null);
}
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
success(xmlHttp.responseText);
}
};
}
以對(duì)象的形式做函數(shù)的參數(shù)還是比較靈活的,不用拘泥于參數(shù)個(gè)數(shù)的問題。但這容易出現(xiàn)一個(gè)問題,就是使用參數(shù)的時(shí)候很有可能參數(shù)沒給卻在函數(shù)內(nèi)部使用了,比如在調(diào)用函數(shù)時(shí)忘了寫success回調(diào)函數(shù),而定義的時(shí)候卻用到了他,這就會(huì)報(bào)錯(cuò)了,因?yàn)閟uccess是undefined了。所以為了避免這種情況我覺得最好在封裝函數(shù)的時(shí)候盡量給每一個(gè)參數(shù)一個(gè)默認(rèn)值,如果調(diào)用的時(shí)候未給出某個(gè)參數(shù)那么他就使用默認(rèn)值代替,這樣就不會(huì)出現(xiàn)上述情況了。
接下來下面是創(chuàng)建XMLHttpRequest對(duì)象,寫了兩種創(chuàng)建方式是為了兼容IE才有的寫法,舊版本的IE瀏覽器不支持XMLHttpRequest構(gòu)造函數(shù),IE有他自己獨(dú)特的構(gòu)造函數(shù)來支持ajax那就是ActiveXObject構(gòu)造函數(shù)。
創(chuàng)建好了XMLHttpRequest對(duì)象,接下來寫的是對(duì)發(fā)送參數(shù)data的轉(zhuǎn)換,在使用ajax函數(shù)的時(shí)候data也用json的數(shù)據(jù)格式會(huì)有一種親切感,因?yàn)榇蟛糠謅jax傳輸?shù)臅r(shí)候返回?cái)?shù)據(jù)都使用json格式,所以發(fā)送的時(shí)候也使用json格式顯得很友好。這里需要將{a: b, c: d}的格式轉(zhuǎn)換為a=b&c=d的格式。
然后是對(duì)"POST"和"GET"兩種不同的發(fā)送方式做處理。GET方法比較簡(jiǎn)單,直接把整理好的數(shù)據(jù)接在open方法的url參數(shù)的后面就行了(要記得在url后面加上"?"),send方法也不用帶參數(shù)了,因?yàn)閰?shù)已經(jīng)在url后面帶著發(fā)過去了,所以send方法的參數(shù)直接給個(gè)null;POST方法這里有個(gè)坑,如果不注意可能會(huì)很煩惱為什么會(huì)得不到想要的結(jié)果,那就是需要設(shè)定Content-Type頭信息,模擬HTTP的POST方法發(fā)送一個(gè)表單,這樣服務(wù)器才會(huì)知道如何處理上傳的內(nèi)容。send方法中參數(shù)的提交格式和GET方法中url的寫法一樣,也是a=b&c=d格式。注意open方法必須放在設(shè)定頭信息的前面,否則也會(huì)報(bào)錯(cuò)。async參數(shù)可以是true也可以是false,true代表使用異步方式調(diào)用,false代表使用同步方式調(diào)用,理所當(dāng)然使用ajax是一定用異步的,這里只是提供一個(gè)選擇,而且他的默認(rèn)值也是true。
最后需要注冊(cè)一個(gè)onreadystatechange事件,當(dāng)XMLHttpRequest對(duì)象的readyState屬性等于4了(代表收到完整的服務(wù)器響應(yīng)了),同時(shí)status屬性等于200(代表服務(wù)器響應(yīng)的狀態(tài)值為OK,狀態(tài)正常)就可以判定這次ajax從發(fā)送過程到響應(yīng)過程全程傳輸成功了,我們可以對(duì)返回的數(shù)據(jù)做一些處理,把要處理的代碼寫在success函數(shù)中,ajax成功就會(huì)調(diào)用之。
// 使用示例
ajax({
method:'POST',
url: 'test.php',
data: {
name1: 'value1',
name2: 'value2' },
success: function (response) {
// codes here }
});