進(jìn)入到Web 2.0時代,技術(shù)上的特征,很大一部分表現(xiàn)在與用戶交互效能的提升。像現(xiàn)在很多流行的電子郵箱的Web界面、Blog程序的界面,都融入了Web 2.0的特征,人們能夠像使用C/S架構(gòu)程序一樣使用它們,而不必淹沒在沒完沒了的頁面刷新當(dāng)中。在激動人心的效能提升之前,JavaScript等腳本技術(shù)就已經(jīng)在交互性上發(fā)揮了很大的作用。
傳統(tǒng)的JavaScript應(yīng)用局限在對頁面內(nèi)容的控制、與DHTML結(jié)合展現(xiàn)網(wǎng)頁特效、驗證用戶輸入數(shù)據(jù)的有效性。在之前也提到過,IFRAME用來在一個頁面中顯示另外一個頁面。將它們結(jié)合在一起,就有了初步異步響應(yīng)機制,用戶不必再苦等網(wǎng)頁的刷新,就能操縱頁面上其他的元素,在服務(wù)器端將數(shù)據(jù)處理好后,會調(diào)用IFRAME所在父頁面的腳本來刷新父頁面元素的內(nèi)容。
使用JavaScript與IFRAME進(jìn)行異步響應(yīng)的示例如例程2-11與例程2-12所示。將例程2-11與例程2-12的程序文件放在相同的文件夾下,就可執(zhí)行。
例程2-11 用戶界面文件index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>JavaScript與IFRAME異步響應(yīng)示例</title>
<script language=javascript>
<!--
function getservertime(){
document.frames['ctrframe'].location.replace("getservertime.html");
//在名為ctrframe的IFRAME中打開getservertime.asp文件
}
function msg(){ //后臺腳本完成響應(yīng)后調(diào)用的函數(shù)
alert("讀取成功!");
}
//-->
</script>
</head>
<body>
<span id="servertime">讀取服務(wù)器時間</span><br>
<input type="button" name="getservertime" id="getservertime" onclick=
"getservertime()"value="讀取">
<iframe name=ctrframe id=ctrframe width=0 height=0></iframe>
</body>
</html>
例程2-12 ASP后臺處理腳本文件GetServerTime.asp
<%
Dim ServerTime
ServerTime=Now()
%>
<html>
<head></head>
<body>
<input type=hidden name=servertime id=servertime value="<%=ServerTime%>">
<script language=javascript>
<!--
parent.document.getElementById("servertime").innerHTML=document.getElementById
("servertime").value; //使用JavaScript的parent對象更新IFRAME的父頁的內(nèi)容
parent.msg(); //調(diào)用父頁的響應(yīng)函數(shù)
//-->
</script>
</body>
</html>
那么,有了JavaScript與IFRAME后,為什么還需要Ajax呢?畢竟JavaScript+IFRAME只是一個折中的方案,雖然能夠在大部分場合應(yīng)用,但還是有一些瑕疵。比如使用這種方法時,雖然用戶見不到網(wǎng)頁的刷新,但是在IE的進(jìn)度條中依然會顯示出IFRAME中頁面刷新的進(jìn)度,單擊按鈕也會發(fā)出當(dāng)網(wǎng)頁刷新或跳轉(zhuǎn)時的音效,讓用戶依然能夠感到頁面進(jìn)行了刷新。況且JavaScript與IFRAME不是專門被設(shè)計用來進(jìn)行異步響應(yīng)處理的,能夠?qū)崿F(xiàn)簡單的文本數(shù)據(jù)傳遞,再復(fù)雜一些的應(yīng)用就無能為力了。
對于用戶來說這些不是什么大問題,但是對于程序員來說遇到復(fù)雜的處理情況,比如不是單單需要簡單的文本數(shù)據(jù),而是要獲取更高級的XML數(shù)據(jù),或者更豐富的內(nèi)容,比如發(fā)出一個HEAD請求,獲取其他有用的信息時,JavaScript+IFRMAE的方式就不能實現(xiàn)這些高級的功能了。
微軟在.NET平臺推出了Atlas來配合ASP.NET實現(xiàn)Web 2.0的特性,那么有的朋友又會擔(dān)心是否ASP將要被淘汰?就目前情況看沒有那么糟糕,至少我們還有Ajax能延續(xù)ASP的輝煌。
Ajax的核心是基于XMLHttpRequest對象,當(dāng)然不要被這個對象的名稱嚇倒,它可以進(jìn)行XML格式數(shù)據(jù)的請求,但是在大多數(shù)應(yīng)用情況下,它是使用文本格式的數(shù)據(jù)進(jìn)行請求的。使用XMLHttpRequest對象,比使用JavaScript+IFRAME的方式進(jìn)行異步響應(yīng)更為干練、更為實用。
[NextPage]
Ajax是Asynchronous JavaScript and XML(及DHTML等)的縮寫,它包括以下幾個基本技術(shù)。
l HTML用于建立Web表單并確定應(yīng)用程序其他部分使用的字段。
l JavaScript代碼是運行Ajax應(yīng)用程序的核心代碼,幫助改進(jìn)與服務(wù)器應(yīng)用程序的通信。
l DHTML或Dynamic HTML,用于動態(tài)更新表單。我們將使用div、span和其他動態(tài)HTML元素來標(biāo)記 HTML。
l 文檔對象模型DOM用于(通過JavaScript代碼)處理HTML結(jié)構(gòu)和(某些情況下)服務(wù)器返回的XML。
看一下使用了Ajax的B/S架構(gòu)程序與傳統(tǒng)的B/S架構(gòu)程序在客戶端和服務(wù)器端進(jìn)行響應(yīng)的區(qū)別,如圖2-1所示。
圖2-1 Ajax的B/S架構(gòu)程序與傳統(tǒng)的B/S架構(gòu)程序在客戶端和服務(wù)器端進(jìn)行響應(yīng)的區(qū)別
圖2-1左半部是傳統(tǒng)B/S架構(gòu)程序的響應(yīng)機制,客戶端(browser client)通過用戶接口,(user interface,通常是網(wǎng)頁)依靠發(fā)送HTTP請求(HTTP Request)直接與服務(wù)器(web server)溝通,待服務(wù)器讀取內(nèi)容后再返回文本格式的數(shù)據(jù)(HTML+CSS data),通過用戶接口呈現(xiàn)給用戶;而使用了Ajax的B/S架構(gòu)程序在用戶接口和服務(wù)器端之間增加了Ajax引擎,用戶在用戶接口通過JavaScript調(diào)用Ajax發(fā)送請求,服務(wù)器端會將數(shù)據(jù)通過文本或XML格式傳送到Ajax引擎,再由Ajax引擎告知用戶。這樣用戶就不必等待頁面的刷新,而是由Ajax引擎通過JavaScript來控制頁面元素的刷新來更新界面內(nèi)容。
Ajax使用是比較簡單的,拋開XML不說,來看看例程2-13與例程2-14通過Ajax來實現(xiàn)的異步響應(yīng)。
例程2-13 HTML用戶界面文件index.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>AJAX test</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<script language=javascript>
//初始化XMLHttpRequest對象
var request = false;
try {
request = new XMLHttpRequest();
}
catch (trymicrosoft) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (othermicrosoft) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (failed) {
request = false;
}
}
}
if (!request){
alert("Error initializing XMLHttpRequest!");
}
function callServer(){
/*從用戶頁面取得數(shù)據(jù)*/
var city=document.AJAXtest.city.value;
var state=document.AJAXtest.state.value;
/*數(shù)據(jù)必須非空*/
if((city==null)||(city==""))return;
if((state==null)||(state==""))return;
/*建立連接字符串*/
var url="GetValueFromClient.asp?city="+escape(city)+"&state=
"+escape(state); //esacape()用來返回為Unicode格式的字串值
/*建立到服務(wù)器的連接*/
request.open("GET",url,true) //最后一個參數(shù)為true,那么將請求一個異步
//鏈接,由Ajax來完成。若為false則請求發(fā)出后將等待服務(wù)器響應(yīng)
/*設(shè)置服務(wù)器在完成后要運行的函數(shù)*/
request.onreadystatechange=updatePage;
/*發(fā)送請求*/
request.send(null); //最后,使用值 null 調(diào)用 send()。因為已經(jīng)在請求
//URL 中添加了要發(fā)送給服務(wù)器的數(shù)據(jù)(city 和 state),所以請求中不
//需要發(fā)送任何數(shù)據(jù)。發(fā)出請求后,服務(wù)器按照您的要求工作
}
function updatePage(){
// 輸出就緒狀態(tài)
/*
try{
alert("updatePage() called with ready state of "
+ request.readyState +" and a response text of '"
+ request.responseText + "'");
}
catch(e1){
alert("Broswer get error.updatePage() called with ready state of "
+ request.readyState)
}
*/
if(request.readyState==4){
/*
0:請求沒有發(fā)出(在調(diào)用 open() 之前);
1:請求已經(jīng)建立但還沒有發(fā)出(調(diào)用 send() 之前);
2:請求已經(jīng)發(fā)出正在處理之中(這里通??梢詮捻憫?yīng)得到內(nèi)容頭部);
3:請求已經(jīng)處理,響應(yīng)中通常有部分?jǐn)?shù)據(jù)可用,但是服務(wù)器還沒有
完成響應(yīng);
4:響應(yīng)已完成,可以訪問服務(wù)器響應(yīng)并使用它。
一些瀏覽器從不報告0或1而直接從2開始,然后是3和4。
其他瀏覽器則報告所有的狀態(tài)。還有一些則多次報告就緒狀態(tài)1
*/
if(request.status==200){ //HTTP狀態(tài)碼為200代表一切順利
var response=request.responseText;
document.AJAXtest.result.value=response;
}
else{
switch(request.status){ //輸出HTTP狀態(tài)碼
case 403:
alert("Access denied.");
break;
case 404:
alert("Requested URL is not found.");
break;
default:
alert("Error!\nThe HTTP status is:"+request.status);
}
}
}
}
function getHeaders_send(){//發(fā)送HEAD請求獲取服務(wù)器信息
/*從用戶頁面取得數(shù)據(jù)*/
var city=document.AJAXtest.city.value;
var state=document.AJAXtest.state.value;
/*數(shù)據(jù)必須非空*/
if((city==null)||(city==""))return;
if((state==null)||(state==""))return;
var url="GetValueFromClient.asp?city="+escape(city)+"&state="+escape(state);
//esacape()用來返回為Unicode格式的字串值
request.open("HEAD",url,true);
request.onreadystatechange=getHeaders_get;
request.send(null);
}
function getHeaders_get(){
if(request.readyState==4){
alert(request.getAllResponseHeaders());
/*
request.getResponseHeader("Content-Length") 獲取響應(yīng)的長度
request.getResponseHeader("Content-Type") 要獲取內(nèi)容類型
*/
}
}
</script>
</head>
<body>
<form name=AJAXtest>
城市:<input type=text name=city>
<br>
?。?lt;input type=text name=state>
<br>
結(jié)果:<input type=text name=result>
<br>
<input type=button value=提交 onclick=callServer()>
<br>
<input type=button value=GetHTTPHeaders onclick=getHeaders_send()>
</form>
</body>
</html>
|
esacape()方法用來返回Unicode格式的字符串,比如:var tmpstring=esacape ("a test")返回a%20test。 |
在此例程中,不僅演示了使用XMLHttpRequest對象發(fā)送GET請求的方法,還演示了發(fā)送HEAD請求獲取更多服務(wù)器信息的方法。
例程2-14 后臺腳本處理腳本文件GetValueFromClient.asp
<%
Dim City,State
Dim Result
City=Request.QueryString("City")
State=Request.QueryString("State")
Function GetResult()
Response.CharSet="GB2312"
Result=State&" Province "&City&" City"
Response.Write Result
End Function
GetResult()
%>
|
在程序中,設(shè)置了Response.CharSet屬性返回中文,如果不設(shè)置Response. CharSet屬性為返回中文,則服務(wù)器端返回的中文數(shù)據(jù)都將是亂碼。 |
在Ajax的開發(fā)中,很多地方都要與DOM(文檔對象模型,Document Object Model的縮寫)打交道。相信學(xué)習(xí)過XML的朋友一定不會陌生,對于那些以前沒有接觸過DOM的朋友,了解它也是很簡單的。網(wǎng)頁的HTML文檔就是基于DOM的,請看例程2-15。
[NextPage]
例程2-15 dom.htm
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>DOM Page</title>
</head>
<body>
<p align=center>這個<i>HTML</i>文檔就是基于<strong>DOM</strong>的。</p>
<p>簡單的示例。</p>
</body>
</html>
這是一個很簡單的網(wǎng)頁,里邊包含了一些元素,它的結(jié)構(gòu)如圖2-2所示。
圖2-2 基于DOM的HTML
每一個方框就是一個節(jié)點(Node),它擁有父節(jié)點和子節(jié)點,比如HEAD元素的父節(jié)點是HTML,子節(jié)點是TITLE和META。最高的一層叫根元素。每個節(jié)點還可以擁有自己的屬性,比如在第一個節(jié)點P中,它擁有一個屬性align,值是center。
對DOM的操作是通過JavaScript進(jìn)行的。
對DOM的操作,包括獲取節(jié)點對象、添加節(jié)點、刪除節(jié)點、修改節(jié)點屬性等操作,在此不贅述了,有興趣的朋友可以去閱讀相關(guān)資料。
Microsoft的IE使用 MSXML 解析器處理 XML,IE中安裝的 JavaScript 技術(shù)版本不同,MSXML 實際上有兩種不同的版本,因此必須對這兩種情況分別編寫代碼,用來創(chuàng)建XMLHttpRequest對象,參見例程2-16。
例程2-16 在IE中創(chuàng)建XMLHttpRequest對象
var xmlHttp = false;
try {
//嘗試使用Msxml2.XMLHTTP名稱創(chuàng)建對象
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
//嘗試使用Microsoft.XMLHTTP名稱創(chuàng)建對象
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e2) {
xmlHttp = false;
}
}
在非IE的瀏覽器中,實際就是用一行代碼創(chuàng)建對象:
var xmlHttp = new XMLHttpRequest object;
這種方法支持Mozilla、Firefox、Safari、Opera等非IE瀏覽器。
綜合上述方法,整理出在任何瀏覽器中都可以創(chuàng)建XMLHttpRequest對象的方法,參見例程2-17。
例程2-17 在任何瀏覽器中都可以創(chuàng)建XMLHttpRequest對象的方法
var xmlHttp = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
//嘗試在IE瀏覽器中創(chuàng)建XMLHttpRequest對象
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e2) {
xmlHttp = false;
}
}
@end @*/
//若創(chuàng)建對象失敗,則使用非IE瀏覽器的方法創(chuàng)建XMLHttpRequest對象
if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
xmlHttp = new XMLHttpRequest();
}
|
@cc_on語句激活腳本引擎中的條件編譯,使不支持條件編譯的瀏覽器將你的腳本視為有效語法而接受它,在注釋外的一個@if或@set語句也將激活條件編譯。 |
有的朋友嘗試把創(chuàng)建XMLHttpRequest對象的代碼寫入到一個方法當(dāng)中,當(dāng)使用的時候可以調(diào)用,這種想法是好的,但是忽略了一個問題。如果一個頁面有很多內(nèi)容要填,而用戶的瀏覽器恰好不支持XMLHttpRequest對象,或者因為安全原因關(guān)閉了解析JavaScript腳本,那么當(dāng)用戶填完所有信息時才發(fā)現(xiàn)頁面不能使用,將是一件很惱人的事情。因此建議編寫靜態(tài)的代碼,讓用戶能夠盡早發(fā)現(xiàn)問題。
可以用XMLHttpRequest對象的readyState獲取瀏覽器的就緒狀態(tài)碼。瀏覽器就緒狀態(tài)如下。
l 0:請求沒有發(fā)出(在調(diào)用 open() 之前)。
l 1:請求已經(jīng)建立但還沒有發(fā)出(調(diào)用 send() 之前)。
l 2:請求已經(jīng)發(fā)出正在處理之中(這里通??梢詮捻憫?yīng)得到內(nèi)容頭部)。
l 3:請求已經(jīng)處理,響應(yīng)中通常有部分?jǐn)?shù)據(jù)可用,但是服務(wù)器還沒有完成響應(yīng)。
l 4:響應(yīng)已完成,可以訪問服務(wù)器響應(yīng)并使用它。
在多個 JavaScript 函數(shù)都使用相同的請求對象時,需要檢查就緒狀態(tài) 0 來確保這個請求對象沒有正在使用,這種機制會產(chǎn)生問題。由于 readyState == 4 表示一個已完成的請求,因此使用過程中經(jīng)常會發(fā)現(xiàn)那些目前沒在使用的處于就緒狀態(tài)的請求對象仍然被設(shè)置成了4,這是因為從服務(wù)器返回來的數(shù)據(jù)已經(jīng)使用過了,但是從它們被設(shè)置為就緒狀態(tài)之后就沒有進(jìn)行任何變化。有一個函數(shù) abort() 會重新設(shè)置請求對象,但是這個函數(shù)卻不是真正為了這個目的而使用的。如果程序必須使用多個函數(shù),最好是為每個函數(shù)都創(chuàng)建并使用一個函數(shù),而不是在多個函數(shù)之間共享相同的對象。
不同的瀏覽器返回的就緒狀態(tài)不同。一些瀏覽器從不報告0或1而直接從2開始,然后是3和4;其他瀏覽器則報告所有的狀態(tài);還有一些則多次報告就緒狀態(tài)1。這也是需要注意的。比如相同的代碼,IE和Firefox 1.5會報告1、2、3、4,而Safari 2.0.1會報告2、3、4,Opera 8.5則只會報告3、4。
初次在ASP中使用XMHttpRequest對象的朋友大多都會碰到一個問題:服務(wù)器返回的中文字符串是亂碼,這時由于使用XMLHttpRequest對象從服務(wù)器返回的字符串默認(rèn)編碼是UTF-8所致,解決的辦法就是在ASP腳本中設(shè)置Response對象的CharSet屬性為中文:
Response.CharSet="GB2312"
若處理用戶響應(yīng)的后臺頁面出現(xiàn)錯誤,或者被刪除,那么就不能夠執(zhí)行用戶的操作。這時就需要根據(jù)HTTP狀態(tài)碼來判斷錯誤,以告知用戶??梢允褂肑avaScript的switch…case…default…語句來判斷錯誤代碼,并將其轉(zhuǎn)換成錯誤信息告知用戶,如例程2-18所示:
例程2-18 檢測HTTP狀態(tài)碼
if(request.status==200){ //HTTP狀態(tài)碼為200代表一切順利
var response=request.responseText;
document.AJAXtest.result.value=response;
}
else{
switch(request.status){ //輸出HTTP錯誤
case 403:
alert("沒有訪問權(quán)限");
break;
case 404:
alert("頁面不存在");
break;
default:
alert("出現(xiàn)錯誤!\nHTTP狀態(tài)碼:"+request.status);
}
|
\n的作用是在JavaScript輸出的字符串中換行。 |
如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會為你解答!! 點擊進(jìn)入論壇