|
初次接觸AJAX的開發(fā)人員一定很關(guān)心:如何在實際環(huán)境中使用 AJAX,以及如何評估它在項目中的價值。本文從基本操作入手,結(jié)合模擬實例,由淺入深介紹了AJAX的入門之道。 AJAX入門 ● 如何發(fā)送HTTP請求 為了使用JavaScript向服務(wù)器發(fā)送HTTP請求,需要為提供這種功能的類創(chuàng)建實例。這種類最先作為ActiveX對象: XMLHTTP被引入到Internet Explorer里面。后來,Mozilla、Safari及其他瀏覽器紛紛仿效,實現(xiàn)了XMLHttpRequest類,支持微軟的原始ActiveX對象所具有的方法和屬性。 因此,為了為所需的類創(chuàng)建跨瀏覽器的實例(對象),可編寫如下代碼。(為了便于闡述,該代碼是用于創(chuàng)建XMLHTTP實例的簡化版。) if (window.XMLHttpRequest) { // Mozilla, Safari, ... http_request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE http_request = new ActiveXObject("Microsoft.XMLHTTP"); } 如果來自服務(wù)器的響應(yīng)沒有XML mime-type頭,一些Mozilla瀏覽器的某些版本可能無法正常工作。為了解決這個問題,如果服務(wù)器發(fā)送的頭不是text/xml,可調(diào)用另外方法來忽略該頭。 http_request = new XMLHttpRequest(); http_request.overrideMimeType(‘text/xml‘); 下一步就是確定收到服務(wù)器對請求的響應(yīng)后,需要做什么。在這個階段,需要告訴HTTP請求對象: 哪個JavaScript函數(shù)將完成處理響應(yīng)的工作??梢园褜ο蟮膐nreadystatechange屬性設(shè)成準備使用的JavaScript的函數(shù)的名稱,如下所示: http_request.onreadystatechange = nameOfTheFunction; 注意,函數(shù)名后面沒有方括號,也無需傳遞參數(shù)。另外,可以使用迅速定義函數(shù)的Javascript技術(shù),定義會立即處理響應(yīng)的動作,而不是賦予函數(shù)名,如下所示: http_request.onreadystatechange = function(){ // 完成工作}; 聲明了一旦收到響應(yīng)會發(fā)生什么動作后,就要實際發(fā)送請求了。需要調(diào)用HTTP請求類的open()和send()方法,如下所示: http_request.open(‘GET‘, ‘http://www./some.file‘, true); http_request.send(null); open()調(diào)用的第一個參數(shù)是HTTP請求方法——GET、POST、HEAD或者其他任何得到服務(wù)器支持的方法。按照HTTP標準,方法需要大寫,否則,有些瀏覽器(如Firefox)可能無法處理請求。第二個參數(shù)是請求頁面的URL。作為一項安全特性,無法調(diào)用第三方域名上的頁面。所有頁面上務(wù)必使用準確的域名,否則如果調(diào)用open(),會得到“權(quán)限被拒絕”的錯誤提示。一個常見的錯誤就是按照domain.tld來訪問網(wǎng)站,卻試圖使用www.domain.tld調(diào)用頁面。第三個參數(shù)確定了請求是不是異步模式。如果是TRUE,那么即使服務(wù)器響應(yīng)還沒有到達,JavaScript函數(shù)仍繼續(xù)執(zhí)行。這就是AJAX中的“A”。 如果請求方法是POST,那么send()方法的參數(shù)可以是想發(fā)送給服務(wù)器的任何數(shù)據(jù)。數(shù)據(jù)應(yīng)當采用查詢字符串的格式,如下所示: name=value&anothername=othervalue&so=on 注意,如果想使用POST發(fā)送請求,必須使用以下代碼行來改變請求的MIME類型,否則,服務(wù)器會丟棄通過POST發(fā)送的數(shù)據(jù)。 http_request.setRequestHeader(‘Content-Type‘, ‘a(chǎn)pplication/x-www-form-urlencoded‘); ● 處理服務(wù)器響應(yīng) 切記,在發(fā)送請求時,要提供旨在處理響應(yīng)的JavaScript函數(shù)的名稱。 http_request.onreadystatechange = nameOfTheFunction; 不妨看一下這個函數(shù)的功能。首先,函數(shù)需要檢查請求的狀態(tài)。如果狀態(tài)的值為4,就意味著完整的服務(wù)器響應(yīng)已收到,可以繼續(xù)處理響應(yīng)。readyState值如下: 0(未初始化)、1(正在加載)、2(加載完畢)、3(可以交互)、4(完成)。 if (http_request.readyState == 4) { // 一切正常,響應(yīng)已收到 } else { // 還沒有就緒 } 下一步就是檢查HTTP服務(wù)器響應(yīng)的狀態(tài)代碼。所有可能的狀態(tài)代碼都列在W3C的網(wǎng)站上(http://www./Protocols/rfc2616/rfc2616-sec10.html)。這里只對200 OK響應(yīng)感興趣。 if (http_request.status == 200) { // 非常好! } else { // 請求有問題, // 譬如響應(yīng)可能是404(未發(fā)現(xiàn)) // 或者500(內(nèi)部服務(wù)器錯誤)響應(yīng)代碼 } 檢查了請求狀態(tài)及響應(yīng)的HTTP狀態(tài)代碼后,就可以對服務(wù)器發(fā)送過來的數(shù)據(jù)進行各種處理了。有兩種方式來訪問該數(shù)據(jù): 一是http_request.responseText,將返回文本字符串形式的服務(wù)器響應(yīng); 二是http_request.responseXML,將返回XMLDocument對象形式的響應(yīng)??梢杂肑avaScript DOM函數(shù)來遍歷XMLDocument對象。 ● 簡單示例 我們把所有部分結(jié)合起來,發(fā)送簡單的HTTP請求。我們的JavaScript將請求一個HTML文檔: test.html,該文檔包含“I‘m a test.”文本,然后我們用alert()方法顯示test.html文件的內(nèi)容。 < script type="text/javascript" language="javascript"> var http_request = false; function makeRequest(url) { http_request = false; if (window.XMLHttpRequest) { // Mozilla, Safari,... http_request = new XMLHttpRequest(); if (http_request.overrideMimeType) { http_request.overrideMimeType(‘text/xml‘); } } else if (window.ActiveXObject) { // IE try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } if (!http_request) { alert(‘Giving up :( Cannot create an XMLHTTP instance‘); return false; } http_request.onreadystatechange = alertContents; http_request.open(‘GET‘, url, true); http_request.send(null); } function alertContents() { if (http_request.readyState == 4) { if (http_request.status == 200) { alert(http_request.responseText); } else { alert(‘There was a problem with the request.‘); } } } < /script> < span style="cursor: pointer; text-decoration: underline" onclick="makeRequest(‘test.html‘)"> Make a request < /span> 在這個示例中,用戶點擊瀏覽器上面的“發(fā)送請求”鏈接; 調(diào)用makeRequest()函數(shù),參數(shù)是同一目錄下的HTML文件名: test.html; 請求被發(fā)送,然后onreadystatechange執(zhí)行結(jié)果被傳遞給alertContents(); alertContents()檢查響應(yīng)是否被收到、是否正常,然后用alert()方法顯示test.html文件的內(nèi)容。 如果XMLHttpRequest調(diào)用的頁面不是有效的XML(譬如不是明文),上面的代碼行“http_request.overrideMimeType(‘text/xml‘);”就會導致Firefox 1.5b里面出現(xiàn)Javascript 控制臺錯誤信息。如果瀏覽器上出現(xiàn)了“語法錯誤”或者“不規(guī)范的錯誤”,而且不是試圖從XMLHttpRequest加載XML頁面,請從代碼中刪除該行。 另外,如果把請求發(fā)送到將返回XML的一段代碼,而不是發(fā)送到靜態(tài)的XML文件,要是頁面在Mozilla和IE瀏覽器中都能正常工作,就必須設(shè)置一些響應(yīng)頭。如果沒有設(shè)置頭: “Content-Type: application/xml”,IE會在試圖訪問XML元素的那一行后面拋出Javascript錯誤: “Object Expected”。如果沒有設(shè)置頭: “Cache-Control: no-cache”,瀏覽器就會緩存響應(yīng),永遠不會重新提交請求。這樣一來,調(diào)試起來就會難度很大。 ● 處理XML響應(yīng) 在前一個示例中,收到HTTP請求的響應(yīng)后,我們使用了請求對象的reponseText屬性,該屬性包含test.html文件的內(nèi)容?,F(xiàn)在我們來試一試responseXML屬性。 首先,我們創(chuàng)建一個有效的XML文檔,隨后我們將對其發(fā)出請求。該文檔(test.xml)含有以下代碼: < ?xml version="1.0" ?> I‘m a test.
在腳本中,我們只要修改請求代碼行: onclick="makeRequest(‘test.xml‘)"> 然后在alertContents()中,我們需要把alert()代碼行alert(http_request.responseText): var xmldoc = http_request.responseXML; var root_node = xmldoc.getElementsByTagName(‘root‘).item(0); alert(root_node.firstChild.data); 這樣一來,我們獲得了responseXML提供的XMLDocument對象,然后我們使用DOM方法訪問XML文件里面所含的一些數(shù)據(jù)。 何時使用AJAX 已經(jīng)知道了AJAX的基本知識,下一步無疑就是確定要不要在項目中使用它。要記住的最重要一點就是,如果沒有刷新頁面,就無法使用“后退”按鈕。要把注意力集中于項目中可能得益于使用這種交互的一小部分。譬如說,可以創(chuàng)建一個表單: 每當用戶鍵入輸入字段,或者鍵入字母,就可以查詢腳本,以便提供實時驗證功能??梢詣?chuàng)建拖放頁面: 一釋放項目,就可以把數(shù)據(jù)發(fā)送到腳本中,并把頁面狀態(tài)保存到數(shù)據(jù)庫?,F(xiàn)在確實存在使用AJAX的理由,這不但有助于開發(fā)體驗,還有助于用戶,它完全取決于實際情況和執(zhí)行狀況。 還有其他方法可以避開“后退”按鈕方面的問題,譬如使用Google Gmail: 它現(xiàn)在可以為已經(jīng)完成的操作步驟提供撤消功能,用不著刷新頁面。以后肯定會出現(xiàn)許多更有創(chuàng)意的例子,為開發(fā)人員提供諸多方法來創(chuàng)建獨特、實時的體驗,從而讓用戶成為受益者。 假定讀者已經(jīng)對AJAX的JavaScript和XML兩個部分有一定了解。雖然開發(fā)人員可以通過AJAX請求任何類型的文本文件,但這里將著重討論XML類型。本文創(chuàng)建了一個示例項目。這個示例是一個簡單的請求,要求加載含有頁面內(nèi)容的XML文件,然后解析數(shù)據(jù),把它顯示在HTML頁面上。 表1和表2介紹了Windows Internet Explorer 5、Mozilla、Netscape 7、Safari 1.2和Opera支持的屬性和方法。 ![]() ![]() ● 從何處開始 首先,需要創(chuàng)建一個XML文件,隨后我們會對其進行請求,并作為頁面內(nèi)容來解析。這里請求的那個文件必須與完成的項目位于同一服務(wù)器上。 下一步,創(chuàng)建將發(fā)出請求的HTML文件。頁面使用主體標記中的裝載方法進行裝載時,就會發(fā)生請求。然后,文件需要帶有ID的div標記,那樣我們準備好顯示內(nèi)容后,就可以確定目標。完成了這些步驟后,頁面主體的樣子應(yīng)當如下: <body onload="makeRequest(‘xml/content.xml‘);"> <div id="copy"></div> </body> ● 創(chuàng)建請求對象 為了創(chuàng)建請求對象,必須檢查瀏覽器使用的是XMLHttpRequest還是ActiveXObject。這兩個對象之間的區(qū)別主要在于使用它們的瀏覽器。Windows IE 5 及以上版本使用ActiveX對象; 而Mozilla、Netscape 7、Opera和Safari 1.2及以上版本使用XMLHttpRequest對象。另一個區(qū)別在于創(chuàng)建對象的方式: Opera、Mozilla、Netscape和Safari允許只要調(diào)用該對象的構(gòu)造函數(shù),但Windows IE需要將對象名稱傳遞到ActiveX構(gòu)造函數(shù)中。下面這個示例表明了如何編寫代碼來確定使用哪個對象、如何創(chuàng)建對象: if(window.XMLHttpRequest) { request = new XMLHttpRequest();} else if(window.ActiveXObject) { request = new ActiveXObject("MSXML2.XMLHTTP");} ● 發(fā)出請求 請求對象創(chuàng)建好后,就可以準備向服務(wù)器發(fā)出請求了。為事件處理器創(chuàng)建引用,以偵聽onreadystatechange。隨后,事件處理器方法在狀態(tài)發(fā)生變化時會做出響應(yīng)。一旦完成了請求,就可以創(chuàng)建這個方法。打開連接,GET或者POST定制的URL——這里是content.xml,然后設(shè)置布爾值,定義是否希望調(diào)用異步調(diào)用。 現(xiàn)在可以發(fā)出請求了。示例中使用了null,因為我們用的是GET; 想用POST,則需要用這個方法發(fā)送一個查詢字符串: request.onreadystatechange = onResponse; request.open("GET". url, true); request.send(null); ● 定制加載和錯誤處理消息 為onreadystatechange方法創(chuàng)建的事件處理器是專門負責加載及錯誤處理的地方。在示例中,為所有加載狀態(tài)代碼提供了反饋,還為最經(jīng)常發(fā)生的錯誤處理狀態(tài)代碼提供了一些基本反饋。為了顯示請求對象的當前狀態(tài),readyState屬性包括表3中顯示的一些值。 ![]() W3C詳細列出了HTTP狀態(tài)代碼的定義。我選擇了其中兩個狀態(tài)代碼: 200,請求已成功; 404,服務(wù)器沒有找到與請求文件相匹配的任何東西。 最后,我們檢查了會生成錯誤并提供一般錯誤信息的其他狀態(tài)代碼。下面是一個代碼示例,可以用該代碼處理這些情況。不過要注意,這里把目標定于我們在HTML文件的主體中創(chuàng)建的div ID,并且使用innerHTML方法,添加了裝載以及/或者錯誤消息——該方法設(shè)置了div對象的開始和結(jié)束標記之間的HTML: if(obj.readyState == 0) { document.getElementById(‘copy‘).innerHTML = "Sending Request...";} if(obj.readyState == 1) { document.getElementById(‘copy‘).innerHTML = "Loading Response...";} if(obj.readyState == 2) { document.getElementById(‘copy‘).innerHTML = "Response Loaded...";} if(obj.readyState == 3) { document.getElementById(‘copy‘).innerHTML = "Response Ready...";} if(obj.readyState == 4){ if(obj.status == 200){ return true; } else if(obj.status == 404) { // 把定制消息添加到另一個頁面上,或者把用戶重定向到另一個頁面上 document.getElementById(‘copy‘).innerHTML = "File not found"; } else {document.getElementById(‘copy‘).innerHTML = "There was a problem retrieving the XML."; } } 如果狀況代碼為200,這意味著請求成功,響應(yīng)可以隨時準備解析了。 ● 解析響應(yīng) 準備好解析請求對象的響應(yīng)時,真正的工作開始了。這時候就可以真正開始處理所請求的數(shù)據(jù)了。為了便于在開發(fā)過程中進行測試,responseText和responseXML屬性可用來顯示來自響應(yīng)的原始數(shù)據(jù)。為了開始訪問XML響應(yīng)中的節(jié)點,先從已創(chuàng)建的請求對象入手,定位responseXML屬性,檢索來自響應(yīng)的XML。然后定位documentElement,它會檢索XML響應(yīng)的根節(jié)點的引用。 var response = request.responseXML.documentElement; 已經(jīng)有了響應(yīng)根節(jié)點的引用,這時你可以使用getElementsByTagName(),按節(jié)點名稱來檢索childNodes。下面一行用頭的nodeName來定位childNode: response.getElementsByTagName(‘header‘)[0].firstChild.data; 使用firstChild.data就可以訪問元素里面的文本: response.getElementsByTagName(‘header‘)[0].firstChild.data; 以下是如何編寫代碼的完整示例: var response = request.responseXML.documentElement; var header = response.getElementsByTagName(‘header‘)[0].firstChild.data; document.getElementById(‘copy‘).innerHTML = header; (沈建苗編譯) 雖然AJAX允許我們以新穎的方式與網(wǎng)頁進行交互,可是作為開發(fā)人員,我們需要牢記產(chǎn)品并不單單涉及技術(shù),還涉及用戶以及他們?nèi)绾闻c產(chǎn)品進行交互。要是沒有用戶,我們構(gòu)建的項目將毫無用處。如果時時考慮到這條準則,我們就能評估使用什么技術(shù)、何時使用它們,從而創(chuàng)建有助于所有使用者的應(yīng)用程序。 |
|
|