|
客戶端所嵌入的頁面特定的控制邏輯以JavaScript代碼的形式存在。頁面與JavaScript的交互建立在事件的基礎(chǔ)上(比如文檔加載事件、鼠標點擊事件、焦點變化事件、甚至一個時鐘事件)。AJAX清楚的將表示邏輯和數(shù)據(jù)分離開來、一個HTML網(wǎng)頁能夠在需要的時候獲取以比特為單位的數(shù)據(jù)片段!這不同于以前的有一點變化就必須刷新整個頁面的做法。同時AJAX也需要一種完全不同的服務(wù)端架構(gòu)來支持這種交互模式。以前的傳統(tǒng)服務(wù)端WEB應(yīng)用專注于為每一個客戶端的每一次請求生成HTML頁面、每一次客戶端接到響應(yīng)都要刷新和重新渲染整個頁面。而我們所談的WEB應(yīng)用專注于客戶端把HTML文檔當作模版或容器、客戶端向其中插入內(nèi)容、其原理就是每當客戶端發(fā)生事件、客戶端都可以向服務(wù)端發(fā)出請求并使用服務(wù)端返回的XML數(shù)據(jù)。 名為ValidateServlet的Servlet驗證表單數(shù)據(jù)、但是要求不能對整個頁面刷新。步驟如下: 1. A client event occurs.——客戶端事件發(fā)生: 點擊鏈接或表單元素的鍵盤事件引發(fā)JavaScript函數(shù)validate(): <input type="text" size="20" id="userid" name="id" onkeyup="validate();"> 2. A XMLHttpRequest object is created and configured.——一個XMLHttpRequest對象被創(chuàng)建并配置: var req; function validate() { var idField = document.getElementById("idField"); var url = "validate?id=" + escape(idField.value); if (window.XMLHttpRequest) { req = new XMLHttpRequest(); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP");——創(chuàng)建XMLHttpRequest對象 } req.open("GET", url, true);——調(diào)用XMLHttpRequest對象的open方法、url為所請求的服務(wù)端組件路徑、true表示這個調(diào)用是異步的、 如果設(shè)置為異步就必須還要有一個callback函數(shù)如下: req.onreadystatechange = callback; req.send(null); } 3. The XMLHttpRequest object makes a call.——XMLHttpRequest對象發(fā)出請求: 如果是GET請求那么內(nèi)容可以為空、在url附加參數(shù)。 如果是POST請求那么就需要一個Content-Type頭的設(shè)置如下: req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); req.send("id=" + escape(idTextField.value)); 如果用JavaScript產(chǎn)生表單元素值、必須確保值編碼的正確、JavaScript有一個escape()函數(shù)用于保障正確的編碼、并把特定字符正確的忽略掉。 4. The request is processed by the ValidateServlet.——請求被ValidateServlet所處理: servlet處理XMLHttpRequest就和處理其他HTTP請求一樣: public class ValidateServlet extends HttpServlet { private ServletContext context; private HashMap users = new HashMap(); public void init(ServletConfig config) throws ServletException { this.context = config.getServletContext(); users.put("greg","account data"); users.put("duke","account data"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String targetId = request.getParameter("id"); if ((targetId != null) && !users.containsKey(targetId.trim())) { response.setContentType("text/xml"); response.setHeader("Cache-Control", "no-cache"); response.getWriter().write("valid"); } else { response.setContentType("text/xml"); response.setHeader("Cache-Control", "no-cache"); response.getWriter().write("invalid"); } } } 5. The ValidateServlet returns an XML document containing the results.——ValidateServlet返回一個包含結(jié)果的XML文檔。 ValidateServlet生成一個XML文檔作為響應(yīng)、更復(fù)雜的情況可能用到DOM、XSLT等。 response.setContentType("text/xml"); response.setHeader("Cache-Control", "no-cache"); response.getWriter().write("invalid"); 開發(fā)者必須了解兩件事:第一:Content-Type必須設(shè)置為text/xml;第二:Cache-Control必須設(shè)置為no-cache。 6. The XMLHttpRequest object calls the callback() function and processes the result. ——XMLHttpRequest對象調(diào)用callback()函數(shù)并處理結(jié)果。 XMLHttpRequest對象的準備狀態(tài)有所變化的時候則調(diào)用callback()方法、我們假定已經(jīng)請求完畢ValidateServlet、準備狀態(tài)為4、表示XMLHttpRequest調(diào)用已經(jīng)完成、HTTP狀態(tài)碼為200、表示HTTP交互已經(jīng)成功。 function callback() { if (req.readyState == 4) { if (req.status == 200) { // update the HTML DOM based on whether or not message is valid } } } 瀏覽器維護著一個文檔的對象表示模型、既:DOM。網(wǎng)頁中的JavaScript方法可以訪問這個模型、并且可以在頁面已經(jīng)全部加載完成后再次改變這個模型。 使用JavaScript代碼:req.responseXML可以得到服務(wù)端返回的XML文檔、req為XMLHttpRequest對象、DOM為JavaScript提供了一種搜索文檔內(nèi)容以及根據(jù)搜索結(jié)果改變網(wǎng)頁DOM的手段??梢允褂胷eq.responseText來訪問返回的XML文檔的字符串表示、如下所示: <message> valid </message> 上面的例子是一個簡單的XML片段、實際應(yīng)用可能包含更多: function parseMessage() { var message = req.responseXML.getElementsByTagName("message")[0]; setMessage(message.childNodes[0].nodeValue); } parseMessages()方法處理從服務(wù)端返回的XML文檔、該方法使用message元素的值去調(diào)用setMessage()方法來改變HTML DOM。 7. The HTML DOM is updated.——HTML文檔對象被更新。 JavaScript可以獲得HTML DOM中任何元素(對象)的引用、推薦使用document.getElementById("userIdMessage")方法來獲取。userIdMessage就是網(wǎng)頁上任意元素的ID屬性、有了元素(對象)的引用、JavaScript就可以改變這個元素的屬性以及這個元素的樣式屬性、還可以增加刪除或改變這個元素的子元素。通用的方法是設(shè)置innerHTML屬性、如下所示: <script type="text/javascript"> function setMessage(message) { var userMessageElement = document.getElementById("userIdMessage"); userMessageElement.innerHTML = "<font color=\"red\">" + message + " </font>"; } </script> <body> <div id="userIdMessage"></div> </body> innerHTML屬性被改變以后網(wǎng)頁可以立即體現(xiàn)出變化、如果innerHTML屬性內(nèi)部包含象<image>、<iframe>這樣的元素、那么其所指定的資源內(nèi)容一樣被瀏覽器解析顯示。 這種方法最大的缺點是在JavaScript代碼里面難于以字符串形式書寫HTML、內(nèi)嵌于JavaScript中的HTML也難以看懂、維護和更改。另外的改變HTML DOM的方法是動態(tài)創(chuàng)建新元素然后將其作為子元素插入目標元素下、如下所示: <script type="text/javascript"> function setMessage(message) { var userMessageElement = document.getElementById("userIdMessage"); var userIdMessageFont = document.getElementById("userIdMessageFont"); var messageElement = document.createTextNode(message); if (userMessageElement.childNodes[0]) { // update the elements userIdMessageFont.replaceChild(messageElement, userIdMessageFont.childNodes[0]); } else { // create the new elements var fontElement = document.createTextNode("font"); fontElement.setAtribute("id", "userIdMessageFont"); fontElement.setAtribute("color", "red"); userMessageElement.appendChild(fontElement); fontElement.appendChild(messageElement); } } </script> <body> <div id="userIdMessage"></div> </body> |
|
|