如何實現(xiàn)不用框架自己寫ajax,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
成都創(chuàng)新互聯(lián)服務(wù)項目包括綏江網(wǎng)站建設(shè)、綏江網(wǎng)站制作、綏江網(wǎng)頁制作以及綏江網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,綏江網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到綏江省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
平常會使用ajax來請求數(shù)據(jù),加載一個庫(框架),或許僅僅maybe就使用了它的ajax部分。
寫個ajax,一來可以經(jīng)歷一下處理問題的過程,提升技術(shù)能力,二來工作中有時真的用不著這么大的一個庫(框架),用自己寫的,何樂不為呢。
先來看看流行的jQuery是怎樣調(diào)用ajax的
$.ajax({ url: 'test.php', //發(fā)送請求的URL字符串 type: 'GET', //發(fā)送方式 dataType: 'json', //預(yù)期服務(wù)器返回的數(shù)據(jù)類型 xml, html, text, json, jsonp, script data: 'k=v&k=v', //發(fā)送的數(shù)據(jù) async: true, //異步請求 cache: false, //緩存 timeout: 5000, //超時時間 毫秒 beforeSend: function(){}, //請求之前 error: function(){}, //請求出錯時 success: function(){}, //請求成功時 complete: function(){} //請求完成之后(不論成功或失敗) });
這樣的調(diào)用是不是很舒適、方便,如果感覺舒適那自己動手寫也參照這種設(shè)計方式,不用太復(fù)雜,滿足所需就好。
先了解ajax的基礎(chǔ)知識
XMLHttpRequest 對象
XMLHttpRequest對象是ajax的核心,通過XMLHttpRequest對象來向服務(wù)器發(fā)異步請求,從服務(wù)器獲得數(shù)據(jù),所有現(xiàn)代瀏覽器(IE7+、Firefox、Chrome、Safari、Opera)均支持 XMLHttpRequest 對象(IE5 和 IE6 使用 ActiveXObject)。
創(chuàng)建一個兼容的XMLHttpRequest對象
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
向服務(wù)器發(fā)送請求
xhr.open(method,url,async);
//method:請求的類型;GET 或 POST
//url:請求的URL
//async:true(異步)或 false(同步)
xhr.send(string);
//將請求發(fā)送到服務(wù)器
//string:僅用于 POST 請求
//GET 比 POST 請求方式更簡單也更快,并且在大部分情況下都能用
//在以下情況中,請使用 POST 請求:
//無法使用緩存文件(更新服務(wù)器上的文件或數(shù)據(jù)庫)
//向服務(wù)器發(fā)送大量數(shù)據(jù)(POST 沒有數(shù)據(jù)量限制)
//發(fā)送包含未知字符的用戶輸入時,POST 比 GET 更穩(wěn)定也更可靠
服務(wù)器響應(yīng)
使用 XMLHttpRequest 對象的 responseText 或 responseXML 屬性獲得來自服務(wù)器的響應(yīng)。
如果來自服務(wù)器的響應(yīng)是 XML,而且需要作為 XML 對象進行解析,請使用 responseXML 屬性。
如果來自服務(wù)器的響應(yīng)并非 XML,請使用 responseText 屬性,responseText 屬性返回字符串形式的響應(yīng)。
onreadystatechange 事件
當(dāng)請求被發(fā)送到服務(wù)器時,我們需要執(zhí)行一些基于響應(yīng)的任務(wù)。每當(dāng) readyState 改變時,就會觸發(fā) onreadystatechange 事件。readyState 屬性存有 XMLHttpRequest 的狀態(tài)信息。
XMLHttpRequest 對象的三個重要的屬性:
onreadystatechange //存儲函數(shù)(或函數(shù)名),每當(dāng) readyState 屬性改變時,就會調(diào)用該函數(shù)
readyState //存有 XMLHttpRequest 的狀態(tài), 從 0 到 4 發(fā)生變化
0: 請求未初始化
1: 服務(wù)器連接已建立
2: 請求已接收
3: 請求處理中
4: 請求已完成,且響應(yīng)已就緒
status //200: "OK", 404: 未找到頁面
在 onreadystatechange 事件中,我們規(guī)定當(dāng)服務(wù)器響應(yīng)已做好被處理的準(zhǔn)備時所執(zhí)行的任務(wù), 當(dāng) readyState等于4 且 status為200 時,表示響應(yīng)已就緒。
xhr.onreadystatechange = function(){ if( xhr.readyState == 4 && xhr.status == 200 ){ //準(zhǔn)備就緒 可以處理返回的 xhr.responseText 或者 xhr.responseXML } };
一個簡單的ajax請求如下:
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); xhr.onreadystatechange = function(){ if( xhr.readyState == 4 && xhr.status == 200 ){ //準(zhǔn)備就緒 可以處理返回的 xhr.responseText 或者 xhr.responseXML } }; xhr.open(method,url,async); xhr.send(string);
補充:1. 發(fā)送GET請求時可能得到的是緩存的結(jié)果,為了避免這種情況,可以向URL 添加一個唯一的 ID,時間戳。2. 如果需要像HTML表單那樣 POST 數(shù)據(jù),使用 setRequestHeader() 來添加 HTTP 頭。然后在 send() 方法中發(fā)送數(shù)據(jù)。
url += (url.indexOf('?') < 0 ? '?' : '&') + '_='+ (+new Date()); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
開始寫自己的ajax
先寫一個基本的,定義好各種參數(shù)選項,供參考
var $ = (function(){ //輔助函數(shù) 序列化參數(shù) function param(data){ //.. } function ajax(opts){ var _opts = { url : '/', //發(fā)送請求URL地址 type : 'GET', //發(fā)送請求的方式 GET(默認), POST dataType : '', //預(yù)期服務(wù)器返回的數(shù)據(jù)類型 xml, html, text, json, jsonp, script data : null, //發(fā)送的數(shù)據(jù) 'key=value&key=value', {key:value,key:value} async : true, //異步請求 ture(默認異步), false cache : true, //緩存 ture(默認緩存), false timeout : 5, //超時時間 默認5秒 load : function(){}, //請求加載中 error : function(){}, //請求出錯時 success : function(){}, //請求成功時 complete : function(){} //請求完成之后(不論成功或失敗) }, aborted = false, key, xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); for(key in opts) _opts[key] = opts[key]; /* if(_opts.dataType.toLowerCase() === 'script'){ //.. } if(_opts.dataType.toLowerCase() === 'jsonp'){ //.. } */ if(_opts.type.toUpperCase() === 'GET'){ if(param(_opts.data) !== ''){ _opts.url += (_opts.url.indexOf('?') < 0 ? '?' : '&') + param(_opts.data); } !_opts.cache && ( _opts.url += (_opts.url.indexOf('?') < 0 ? '?' : '&') + '_='+(+new Date()) ); } function checkTimeout(){ if(xhr.readyState !== 4){ aborted = true; xhr.abort(); } } setTimeout(checkTimeout, _opts.timeout*1000); xhr.onreadystatechange = function(){ if( xhr.readyState !== 4 ) _opts.load && _opts.load(xhr); if( xhr.readyState === 4 ){ var s = xhr.status, xhrdata; if( !aborted && ((s >= 200 && s < 300) || s === 304) ){ switch(_opts.dataType.toLowerCase()){ case 'xml': xhrdata = xhr.responseXML; break; case 'json': xhrdata = window.JSON && window.JSON.parse ? JSON.parse(xhr.responseText) : eval('(' + xhr.responseText + ')'); break; default: xhrdata = xhr.responseText; } _opts.success && _opts.success(xhrdata,xhr); }else{ _opts.error && _opts.error(xhr); } _opts.complete && _opts.complete(xhr); } }; xhr.open(_opts.type,_opts.url,_opts.async); if(_opts.type.toUpperCase() === 'POST'){ xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); } xhr.send(_opts.type.toUpperCase() === 'GET' ? null : param(_opts.data)); } return { ajax: ajax } })();
定義好了參數(shù)選項,來分析一下。其中 dataType 是整個ajax的重點,代碼的簡單或者復(fù)雜都在它了。
在這里dataType為預(yù)期服務(wù)器返回的數(shù)據(jù)類型:xml, html, text, json, jsonp, script
1. 為xml時,來自服務(wù)器的響應(yīng)是XML,使用 responseXML 屬性獲取返回的數(shù)據(jù)
2. 為html、text、json時,使用 responseText 屬性獲取返回的數(shù)據(jù)
a. 為html時,返回純文本HTML信息,其中包含的script標(biāo)簽是否要在插入dom時執(zhí)行 ( 代碼復(fù)雜度+3 )
b. 為json時, 返回JSON數(shù)據(jù),要安全、要便捷、要兼容 ( 代碼復(fù)雜度+2 )
3. 為jsonp時,一般跨域才用它,不用原來的ajax請求了,用創(chuàng)建script法( 代碼復(fù)雜度+2 )
4. 為script時: 要跨域時,不用原來的ajax請求了,用創(chuàng)建script法( 代碼復(fù)雜度+1 ); 不跨域,返回純文本JavaScript代碼, 使用 responseText 屬性獲取返回的數(shù)據(jù) ( 代碼復(fù)雜度+1 )
其中,在html片段中的script標(biāo)簽、jsonp、script,都要用到創(chuàng)建script標(biāo)簽的方式。
處理dataType為json
xhrdata = window.JSON && window.JSON.parse ? JSON.parse(xhr.responseText) : eval('(' + xhr.responseText + ')');
這是最簡單的處理方式了,要JSON兼容,可以用json2.js。
處理dataType為jsonp
jsonp是要通過script標(biāo)簽來請求跨域的,先了解下流程:
這上圖中 a.html中請求了 http://www.b.com/b.php?callback=add (在ajax程序中請求url就是這個鏈接),在b.php中讀取了傳過來的參數(shù) callback=add 根據(jù)獲取到的參數(shù)值(值為add),以JS語法生成了函數(shù)名,并把json數(shù)據(jù)作為參數(shù)傳入了這個函數(shù),返回以JS語法生成的文檔給a.html,a.html解析并執(zhí)行返回的JS文檔,調(diào)用了定義好的add函數(shù)。
在程序中一般采用更通用的方式去調(diào)用,比如下面這個廣泛使用的loadJS函數(shù):
function loadJS(url, callback) { var doc = document, script = doc.createElement('script'), body = doc.getElementsByTagName('body')[0]; script.type = 'text/javascript'; if (script.readyState) { script.onreadystatechange = function() { if (script.readyState == 'loaded' || script.readyState == 'complete') { script.onreadystatechange = null; callback && callback(); } }; } else { script.onload = function() { callback && callback(); }; } script.src = url; body.appendChild(script); }
這樣把請求的url,傳入loadJS函數(shù),得到一樣的結(jié)果。
復(fù)制代碼 代碼如下:
loadJS('http://www.b.com/b.php?callback=add');
因為是動態(tài)創(chuàng)建script,請求成功返回,JS代碼就立即執(zhí)行,如果請求失敗是沒有任何提示的。因此自定義的參數(shù)選項: _opts.success 能調(diào)用,_opts.error不能調(diào)用。
ajax處理jsonp也有兩種情況:
1. 設(shè)置了請求URL后的參數(shù) callback=add 特別是定義了函數(shù)名add,請求成功返回,JS代碼就立即執(zhí)行(這里就是調(diào)用 add({"a":8,"b":2}) )
2. 在_opts.success中處理JSON數(shù)據(jù),就是請求成功返回,JS代碼不執(zhí)行,并把函數(shù)中的參數(shù)挪出來,作為_opts.success的參數(shù)返回( 這里相當(dāng)于處理字符串 'add({"a":8,"b":2})' ,去掉 'add(' 和 ‘)',得到 {"a":8,"b":2} )
處理dataType為html
如果不處理HTML片段中script標(biāo)簽,直接把responseText返回值插入DOM樹就可以了。如果要處理script,就要把HTML片段中的script標(biāo)簽找出來,對買個script單獨處理,并注意是script標(biāo)簽中包含的JS代碼還是通過src請求的。
處理dataType為script
如果要跨域時,用創(chuàng)建script的方式,和處理jsonp類似; 不跨域,使用 responseText 屬性獲取返回的數(shù)據(jù),可以用 eval 來讓代碼執(zhí)行,也可以創(chuàng)建script來執(zhí)行。
function addJS(text) { var doc = document, script = doc.createElement('script'), head = doc.getElementsByTagName('body')[0]; script.type = 'text/javascript'; script.text = text; body.appendChild(script); }
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。