專題:Ajax
什麼是Ajax
Ajax (Asynchronous JavaScript and XML)不是一個新的技術,事實上,它是一些舊有的成熟的技術以一種全新的更加強大的方式整合在一起。
Ajax的關鍵技術
u 使用XHTML(HTML)和CSS構建標準化的展示層
u 使用DOM進行動態顯示和交互
u 使用XML和XSLT進行數據交換和操縱
u 使用XMLHttpRequest異步獲取數據
u 使用JavaScript將所有元素綁定在一起
常見的Ajax成功應用示例
u BACKBASE購物網站
u Google Suggest
u Google Map
Ajax的主要作用
u 改善表單驗證方式,不再需要打開新頁面,也不再需要將整個頁面數據提交
u 不需刷新頁面就可改變頁面內容,減少用戶等待時間 。
u 按需獲取數據,每次只從服務器端獲取需要的數據 。
u 讀取外部數據,進行數據處理整合 。
u 異步與服務器進行交互,在交互過程中用戶無需等待,仍可繼續操作
Ajax思維方式
我們就通過用戶名校驗這個簡單的例子來看看傳統Web應用和AJAX應用開發思維的不同之處。
l 這個最簡單的例子需求如下:用戶在頁面的文本框中輸入想註冊的用戶名,然後點擊校驗按鈕,如果輸入的用戶名爲“wangxingkui”,則提示用戶名已經存在,請重新輸入,否則提示用戶名尚未存在,可以使用此用戶名進行註冊。
l 傳統方式處理:
對於校驗用戶名的需求,我們需要一個html頁面和一個servlet程序。Html頁面中包含文本框和提交按鈕,他們位於一個form表單中,這個表單將請求提交給servlet程序,servlet程序判斷當前的用戶名是否是“wangxingkui”,並給出相應的提示,同時servlet中還生成一個鏈接,用於返回html頁面。
l 從這個例子我們可以看到,傳統Web開發思維模式的一個特點是通過form表單提交請求信息,然後轉向一個新的頁面處理請求,並顯示服務器端返回的信息。
l 你可以嘗試運行一下這些代碼,你會發現作爲用戶的你經歷了:在瀏覽器中輸入用戶名->點擊按鈕提交用戶名給Servlet->瀏覽器轉向Servlet的頁面->等待Servlet處理->Servlet返回響應信息->瀏覽器中看到Servlet頁面的響應信息,當然這其中有幾個過程可能時間短暫到你沒有注意,但這些過程是確實存在。
l Ajax方式處理:
l Html頁面中包含文本框和校驗按鈕,點擊提交按鈕以後,我需要通過javascript獲取文本框中的數據,然後通過XMLHttprequest發送數據給servlet,此外還需要準備用於接收響應的javascript函數,接收到servlet的提示信息後,我需要將這些信息動態的寫在頁面上。servlet程序判斷當前的用戶名是否是“wangxingkui”,並給出相應的提示。
l 注意,AJAX模式下問題分析的方式已經發生了變化:
l servlet不需要返回html頁面的鏈接了,因爲我們不需要跳轉到servlet表示的頁面中,我們只需要獲得servlet頁面產生的結果
l html頁面中我不用表單提交數據了,我的數據通過javascript來獲取,然後通過一個叫做XMLHttprequest的對象發送個servlet。而且我沒有做頁面跳轉
l 我需要一個接收servlet響應信息的javascript函數,我沒有進入servelt代表的頁面查看響應信息,而是把servlet的響應信息接收回來,再顯示在我當前的頁面上。
l 與傳統Web應用模式的流程相比,AJAX應用模式的流程的不同之處
l 當你運行上面的程序,你會發現從用戶的角度來看,與傳統Web應用模式的流程相比,AJAX應用模式的流程是不同的。
l AJAX應用的流程是:在瀏覽器中輸入數據->點擊按鈕提交請求->用戶可以繼續做其他事情;Servlet在處理數據,併發回數據->瀏覽器收到響應->瀏覽器中的當前頁面顯示響應結果,這其中仍然有些過程由於時間短暫使你忽略了它的錯在,但實際上這些過程都是存在的。
l 兩個流程的對比讓我們看到的顯而易見的差別就是AJAX應用中沒有向新頁面跳轉,用戶不需要處於無事可做的等待中。
傳統web應用方式:
在傳統的Web應用模型下,大部分的用戶操作都會發送一個HTTP請求給服務器,然後服務器開始處理(接收數據,執行業務邏輯,訪問數據庫等),最後向瀏覽器返回HTML頁面。當服務器處理請求時,用戶能夠做什麼呢?只有等待!
Ajax應用方式
Ajax應用通過在用戶和服務器之間引入一個媒介(Ajax engine)來異步發送請求,消除了傳統的發送請求-等待-發送請求-等待的特性,極大的提高了用戶體驗。
兩種方式的比較
JavaScript簡介
註釋
u 單行註釋(雙斜槓):
// line1
u 多行註釋:
/* line1
line2 */
u HTML風格註釋(不推薦使用):
<!-- line1
注意,不需要以“-->”來結束
變量
u JavaScript不要求在聲明變量時必須明確指出其數據類型(所以稱JavaScript爲弱類型語言),可以使用統一的關鍵字var進行聲明:
n varage = 33;
n mood= “happy”;
u 但是提前對變量做出聲明是一種良好的編程習慣
u 變量名允許包含字母、數字、美元符號($)和下劃線字符,但不允許包括空格或標點符號
數據類型
u JavaScript變量的類型是由變量的值決定的,可以對同一個變量賦予不同數據類型的值:
n varage = “thirty three”;
n age= 33;
u JavaScript中重要的數據類型:
n 未定義(undefined),變量未定義
n 空(null),變量未初始化
n 字符串(string),可以放在單引號或雙引號中
n 數值(number),可以表示整數、浮點數
n 布爾型(boolean),true或false
n 對象(object)
數組
n 數組用來存儲一組值,使用關鍵字Array來聲明,聲明時可以指明數組的長度:
n varcolors = new Array();
n varcolors = new Array(3);
n 其中new關鍵字可以省略,類似其它語言,數組的下標從0開始,賦值方法也和其它語言類似:
n colors[0]= “red”;
n colors[1]= “black”;
n colors[2]= “white”;
n 還可以使用方括號創建數組時同時初始化:
n varcolors = [“red”, “black”, “white”];
n 使用方括號創建數組對象的簡單方法:
n varcolors = [ ]; //聲明空數組對象
n colors[0]= “red”;
n colors[1]= “black”;
n 通過數組的length屬性可以得到數組中元素的個數。數組的長度可以動態擴展:
n colors[3]= “blue”;
n colors[8]= “grey”;
n 關聯數組:在填充數組時爲每個新元素明確地給出下標:
n colors[“r”]= “red”;
n colors[“b”]= “black”;
運算符
n JavaScript中的算術運算符(+、-、*、/、++、--等)、比較運算符(>、<、=、<=、>=)、條件語句(if、while、for等)
函數
n 使用函數可以避免重複輸入大量相同的內容。JavaScript中使用function關鍵字定義函數:
n function funcname (arg1, arg2, …) {
statements;
}
n 聲明一個簡單的函數:
n function multiply (num1, num2) {
vartotal = num1 * num2;
returntotal;
}
聲明後可以直接調用此函數獲取結果:
var result = multiply(5, 9);
注意,JavaScript中的函數不需聲明返回類型,參數也不需要聲明類型
對象
n JavaScript對象是由一組相關的屬性和方法構成的數據實體。屬性和方法都要使用“.”來訪問:
n object.property
n object.method()
n 使用函數來定義“類”:
n functionPerson() {
this.age = 12;
this.name = “no name”;
this.sayHello = function() {
alert(“Hello” + this.name); //其中this關鍵字不能省略!
}
}
n 使用new關鍵字來創建對象實例:
n varvincent = new Person();
DOM基礎
DOM簡介
n DOM是”DocumentObject Model”(文檔對象模型)的首字母縮寫。當創建了一個網頁並把它加載到Web瀏覽器中時,就會在幕後創建一個文檔對象模型。
n DOM表示被加載到瀏覽器窗口裏的當前頁面:瀏覽器向我們提供了當前頁面的模型,而我們可以通過JavaScript訪問這個模型。
n DOM把一份文檔表示爲一棵樹。
例如有如下html文檔:
<html>
<head>
<title>Trees, tress,everywhere</title>
</head>
<body>
<h1>Tress, tress,everywhere</h1>
<p>Welcome to a<em>really</em>boring page.</p>
<div>
Come again soon.
<imgsrc="come-again.gif" />
</div>
</body>
</html>
瀏覽器加載該頁面並將之轉換爲樹形結構
n DOM樹中的一切是以最外層的HTML包含元素,即html元素開始的。使用樹的比喻,這叫做根元素(rootelement)。
n 從根流出的線表示不同標記部分之間的關係。head和body元素是html根元素的孩子(child);title是head的孩子,而文本 “Trees,trees, everywhere”是title的孩子;相對的,head是title的父親(parent),title是文本 “Trees,trees, everywhere” 的父親。處在同一層次的且互不包含的兩個分支(如head和body)之間稱爲兄弟(sibling)關係。整個樹就這樣組織下去,直到瀏覽器獲得與上圖類似的結構。
n 通常把這樣的樹結構成爲一棵節點樹。
節點node
u DOM文檔是由節點構成的集合,此時的節點是文檔樹上的樹枝或者樹葉。
u DOM中節點的類型:
n 元素節點(elementnode),諸如<head>、<p>、<div>等。元素節點可以包含其它的元素,唯一沒有被包含在其它元素裏的元素是<html>,它是根元素。
n 屬性節點(attributenode),元素或多或少地有一些屬性,屬性可以對元素做出一些具體的描述。因爲屬性總是被放到起始標籤裏,所以屬性節點總是被包含在元素節點中。
n 文本節點(textnode),<h1>元素中包含着文本節點“Trees,trees, everywhere”。
基本DOM方法
n getElementById(id)
n 返回一個給定id屬性的元素節點相對應的對象。這個方法是與document對象相關聯的函數。其中document對象代表着整個HTML文檔並可以用來訪問所有頁面中的元素。
n getElementsByTagName(tagname)
n 返回一個對象數組,它們分別對應着文檔裏的一個特定的元素節點。
n getAttribute()
n 返回對象的屬性值
n setAttribute()
n 修改對象的屬性值
重要DOM屬性
n childNodes
n 可以將節點樹中任何一個元素的所有子元素檢索出來,這個屬性返回一個數組,包含了給定元素節點的全體子元素。
n nodeName
n 返回元素節點的名稱。注意,返回的結果全部是大寫。
n nodeType
n 用來區分節點的類型,元素節點的nodeType屬性值是1,屬性節點的nodeType屬性值是2,文本節點的nodeType屬性值是3。
n nodeValue
n 可以用來存取文本節點的值。對於元素節點或屬性節點這個屬性返回空。
n firstChild和lastChild
n 第一個和最後一個孩子節點。
node.firstChild等價於node.childNodes[0],
node.lastChild等價於node.childNodes[node.childNodes.length–1]
n parentNode
n 返回元素的父節點
n nextSibling
n 返回下一個兄弟節點
改變網頁結構的DOM方法
n createElement(tagname)
n 創建新的元素節點,此方法與document對象相關聯。新建的元素節點並未與節點樹相連。
n appendChild(node)
n 把新建的節點插入到節點樹的某個節點下,成爲這個節點的子節點。
n createTextNode(text)
n 創建文本節點
n insertBefore(newNode,targetNode)
n 把一個新元素插入到一個現有元素的前面
n replaceChild(newChild,oldChild)
n 替換一個孩子節點
n removeChild(node)
n 刪除一個孩子節點
第一個AJAX示例
總結:AJAX應用的五個步驟
1、 創建XMLHttpRequest對象
2、 設置回調函數
3、 使用open方法與服務器建立鏈接
4、 向服務器端發送數據
5、 在回調函數針對不同響應狀態進行處理
需要注意的內容:
1.不同瀏覽器下XMLHttpRequest對象的不同的建立方式
2.設置回調函數時不要加括號
3. open方法三個參數含義,此外還需要注意GET方式和POST方式服務器端地址的不同寫法
4. GET方式和POST方式send的參數的不同之處,以及POST方式下send之前需要設置請求頭信息的工作
5.如何判斷正確的響應數據已經返回,此外還要注意如何獲取響應數據內容。
//index.html
<!DOCTYPEHTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>index.html:ajax 檢驗</title>
<metahttp-equiv="keywords"content="keyword1,keyword2,keyword3">
<metahttp-equiv="description"content="this is my page">
<metahttp-equiv="content-type"content="text/html; charset=gb18030">
<scripttype="text/javascript"src="jslib/verifyOwn.js"></script>
</head>
<body>
用ajax進行檢驗!<br>
<inputtype="text"id="username"/>
<inputtype="button"value="檢驗"onclick="verify()"/>
<divid="result"></div>
</body>
</html>
//AJAXServer.java
publicclassAJAXServer extends HttpServlet {
protectedvoiddoPost(HttpServletRequest httpServletRequest,
HttpServletResponsehttpServletResponse)throws ServletException,
IOException {
doGet(httpServletRequest,httpServletResponse);
}
protectedvoid doGet(HttpServletRequesthttpServletRequest,
HttpServletResponsehttpServletResponse)throws ServletException,IOException{
try {
//request.setCharacterEncoding("UTF-8");
//response.setContentType("text/html;charset=gb18030");
httpServletResponse.setContentType("text/html;charset=utf-8");
PrintWriter out =httpServletResponse.getWriter();
Integer inte = (Integer)httpServletRequest.getSession()
.getAttribute("total");
int temp = 0;
if (inte ==null) {temp = 1; }
else {temp = inte.intValue() + 1; }
httpServletRequest.getSession().setAttribute("total", temp);
// 1.取參數
String old =httpServletRequest.getParameter("name");
// String name = newString(old.getBytes("iso8859-1"),"UTF-8");
String name = URLDecoder.decode(old,"UTF-8");
// 2.檢查參數是否有問題
if (old ==null || old.length() == 0){
out.println("用戶名不能爲空");
} else {
// String name =URLDecoder.decode(old,"UTF-8");
// byte[] by =old.getBytes("ISO8859-1");
// String name = newString(by,"utf-8");
// String name =URLDecoder.decode(old,"utf-8");
// 3.校驗操作
// String name = old;
if (name.equals("wangxingkui")) {
// 4。和傳統應用不同之處。這一步需要將用戶感興趣的數據返回給頁面段,而不是將一個新的頁面發送給用戶
// 寫法沒有變化,本質發生了改變
out.println("用戶名[" + name + "]已經存在,請使用其他用戶名, " + temp);
}else {
out.println("用戶名[" + name + "]尚未存在,可以使用該用戶名註冊, " + temp);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 自定義的verifyOwn.js
var xmlhttp;
function verify() {
//從文本框取數據
var username = document.getElementById("username").value;
// 1.創建XMLHttpRequest對象
if (window.XMLHttpRequest) {
xmlhttp =new XMLHttpRequest();
if (xmlhttp.overrideMineType) {
xmlhttp.overrideMineType("text/xml");
}
} elseif (window.ActiveXObject) {
var activeName = ["MSXML2.XMLHTTP","Microsoft.XMLHTTP" ];
for (var i = 0; i < activeName.length; i++){
try {
xmlhttp =newActiveXObject[activeName[i]];
break;
} catch (e) {
}
}
}
if (!xmlhttp) {
// alert("XMLHttpRequest對象創建失敗!")
return;
} else {
// alert(xmlhttp.readyState);
}
// 2.註冊回調函數
xmlhttp.onreadystatechange =callback;
// 3.設置聯接信息
// get方式
// xmlhttp.open("GET","AJAXServer?name=" +username, true);
// post方式
xmlhttp.open("POST","AJAXServer",true);
xmlhttp.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
xmlhttp.send("name=" + username);
// 4.發送數據,並和服務器端進行交付
// xmlhttp.send(null);
}
function callback() {
// 5.接收響應數據
// alert(xmlhttp.readySrate);
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
varresponseText = xmlhttp.responseText;
var divNode =document.getElementById("result");
divNode.innerHTML =responseText;
} else {
alert("出錯了!");
}
}
}
注意,
u“window.XMLHttpRequest”爲true時表示當前瀏覽器是IE7,IE8,Moxilla或其他瀏覽器,我們就可以使用new XMLHttpRequest()的方式來創建一個XMLHttpRequest對象
lif(xmlhttp.overrideMimetype)這個邏輯的作用是解決部分版本的Mozilla在服務器響應頭信息沒有XML時不能正常工作的問題。
u“window.ActiveXObject”爲true時表示當前的瀏覽器爲IE6.0及以下的版本,要使用new ActiveXObject(控件名)的方式來創建一個XMLHttpRequest對象
u這裏需要注意的是不同版本IE中用於建立XMLHttpRequest對象的控件版本很多。如果使用MSXML數組中的某一個控件名稱成功建立了XMLHttpRequest對象,則跳出循環,如果建立失敗會有異常拋出,被catch以後繼續進行循環,嘗試下一個控件名稱。這裏的控件名稱是按照從新到老的順序排列的,這樣可以保證使用較新版本IE的用戶可以較早成功建立XMLHttpRequest對象。如果沒有建立成功XMLHttpRequest對象,則不能繼續後面與服務器端交互的工作,函數只能返回。
u然後設置回調函數。設置回調函數時只給出回調函數的名稱,後面不要帶括號,因爲帶上括號就變成讓XMLHttpRequest對象的onreadystatechange屬性值等於回調函數的返回值了。
u接下來要做的工作是建立對服務器的調用。這裏第一個參數表示http連接的方法, 一般我們使用“GET”或“POST”方式。第二個參數是服務器端地址,由於使用GET方式,因此要傳送給服務器端的數據也在URL中,這裏我們使用了兩個encodeURI,目的是爲了解決URL中的中文信息在服務器端解碼的問題,配合服務器端的URLDecoder.decode(old,“UTF-8”)語句可以保證中文信息在服務器端也可以正常被解出。第三個參數表示是否採用異步方式進行傳輸,其中true表示採用異步方式,我們在AJAX中看重的就是異步方式,因此這個參數我們通常使用true。
u這裏readyState=4時表示服務器端的響應數據已經被全部接收,readyState還有其他狀態,0=未初始化。1=open方法成功調用以後。2=服務器已經應答客戶端的請求。3=交互中。即Http頭信息已經接收,響應數據尚未接收。4=完成。數據接收完成。
uStatus=200表示http連接狀態正常,如果不是200,則表示http連接有誤,此時回來的數據也不是我們需要的。
u當響應數據全部接收並且http連接狀態正確時,我們就可以接收響應的數據了,這裏使用了xmlhttp.responseText用於以文本形式接收響應的數據,當然也可以用XML方式接收,後面會做詳細介紹。