YauBen.com RSS Feed

HTML5 測試 Internet Explorer 表現奇差

Ajax 由 HTML、JavaScript™ 技術、DHTML 和 DOM 組成,這一傑出的方法可以將笨拙的 Web 介面轉化成互動性的 Ajax 應用程式。


掌握 AJAX

理解 Ajax 及其工作原理,建置網站的一種有效方法

Ajax 由 HTML、JavaScript™ 技術、DHTML 和 DOM 組成,這一傑出的方法可以將笨拙的 Web 介面轉化成互動性的 Ajax 應用程式。揭開 Ajax 核心概念的神秘面紗,包括 XMLHttpRequest 物件。Ajax 不僅僅是一種時尚,它是一種建置網站的強大方法,而且不像學習一種全新的語言那樣困難。但在詳細探討 Ajax 是什麼之前,先讓我們瞭解 Ajax 是做什麼。目前,設計應用程式時有兩種基本的選擇:

1. 視窗應用程式
2. Web 應用程式

兩者是類似的,視窗應用程式通常以 CD 為媒體,並完全安裝到電腦上。視窗應用程式可能使用網際網路下載更新,但執行這些應用程式的程式碼在視窗電腦上。

不過,更重要的是 Web 應用程式如何執行以及如何與其進行互動。視窗應用程式一般很快,具有漂亮的使用者介面和非凡的動態性。可以點選、選擇、輸入、打開功能表和子功能表、到處悠遊,基本上不需要等待。

另一方面,Web 應用程式是最新潮流,它們提供了在視窗上不能實現的服務。顯然這樣說過於簡略了,但基本的概念就是如此。您可能已經猜到,Ajax 嘗試建立視窗應用程式的功能和互動性,與不斷更新的 Web 應用程式之間的橋樑。可以使用像桌面應用程式中常見的動態用戶介面和漂亮的控制項,不過是在 Web 應用程式中。

老技術,新技巧

在談到 Ajax 時,實際上涉及到多種技術,要靈活地運用它必須深入瞭解這些不同的技術。好消息是您可能已經非常熟悉其中的大部分技術,更好的是這些技術都很容易學習,並不像完整的程式語言(如 Java)那樣困難。

Ajax 的定義

Ajax 是 Asynchronous JavaScript and XML(以及 DHTML 等)的縮寫。這個縮寫是 Adaptive Path 的 Jesse James Garrett 發明的。下面是 Ajax 應用程式所用到的基本技術:

  • HTML 用於建立 Web 表單並確認應用程式其他部分使用的欄位。
  • JavaScript 程式碼是執行 Ajax 應用程式的核心程式碼,幫助改進與伺服器應用程式的通訊。
  • DHTML 或 Dynamic HTML,用於動態更新表單。我們將使用 div、span 和其他動態 HTML 元素來標記 HTML。
  • 文件物件模型 DOM 用於(透過 JavaScript 程式碼)處理 HTML 結構和(某些情況下)伺服器返回的 XML。
  • 我們來進一步分析這些技術的職責。以後的文章中我將深入討論這些技術,目前只要熟悉這些元件和技術就可以了。對這些程式碼越熟悉,就越容易從對這些技術的零散瞭解轉變到真正把握這些技術(同時也真正打開了 Web 應用程式開發的大門)。

XMLHttpRequest 對象

要瞭解的一個物件可能對您來說也是最陌生的,即 XMLHttpRequest。這是一個 JavaScript 物件,建立該物件很簡單,如下所示。

建立新的 XMLHttpRequest 物件

<script language="javascript" type="text/javascript">
var xmlHttp = new XMLHttpRequest();
</script>

透過 XMLHttpRequest 物件與伺服器進行對話的是 JavaScript 技術。這不是一般的應用程式流,這恰恰是 Ajax 的強大功能的來源。

在一般的 Web 應用程式中,使用者填寫表單文字欄位並點選 Submit 按鈕。然後整個表單傳送到伺服器,伺服器將它轉傳給處理表單的腳本(通常是 PHP 或 Java,也可能是 CGI 程式或者類似的東西),腳本執行完成後再傳送回全新的頁面。該頁面可能是帶有已經填寫某些資料的新表單的 HTML,也可能是確認頁面,或者是具有根據原來表單中輸入資料選擇的某些選項的頁面。當然,在伺服器上的腳本或程式處理和返回新表單時使用者必須等待。螢幕變成一片空白,等到伺服器傳回資料後再重新繪製。這就是互動性差的原因,用戶得不到立即回饋,因此感覺不同於視窗應用程式。

Ajax 基本上就是把 JavaScript 技術和 XMLHttpRequest 物件放在 Web 表單和伺服器之間。當使用者填寫表單時,資料發送給一些 JavaScript 程式碼而不是 直接傳送給伺服器。相反,JavaScript 程式碼接獲表單數據並向伺服器發送請求。同時使用者螢幕上的表單也不會閃爍、消失或延遲。換句話說,JavaScript 程式碼在幕後傳送請求,使用者甚至不知道請求的發出。更好的是,請求是非同步傳送的,就是說 JavaScript 程式碼(和使用者)不用等待伺服器的回應。因此使用者可以繼續輸入資料、拉動螢幕和使用應用程式。

然後,伺服器將資料傳回 JavaScript 程式碼(仍然在 Web 表單中),後者決定如何處理這些資料。它可以迅速更新表單數據,讓人感覺應用程式是立即完成的,表單沒有提交或更新而使用者得到了新資料。JavaScript 程式碼甚至可以對收到的資料執行某種計算,再發送另一個請求,完全不需要用戶干預!這就是 XMLHttpRequest 的強大之處。它可以根據需要自行與伺服器進行互動,使用者甚至可以完全不知道幕後發生的一切。結果就是類似於桌面應用程式的動態、快速回應、高交互性的體驗,但是背後又擁有網際網路的完全強大力量。

加入一些 JavaScript

得到 XMLHttpRequest 的控制碼後,其他的 JavaScript 程式碼就非常簡單了。事實上,我們將使用 JavaScript 程式碼完成非常基本的任務:

取得表單數據:JavaScript 程式碼很容易從 HTML 表單中取得資料並傳送到伺服器。
修改表單上的資料:更新表單也很簡單,從設置欄位值到迅速替換圖像。
解析 HTML 和 XML:使用 JavaScript 程式碼操縱 DOM(請參閱 下一節),處理 HTML 表單伺服器傳回的 XML 資料的結構。
對於前兩點,需要非常熟悉 getElementById() 方法,如下所示。

用 JavaScript 程式碼獲取和設置欄位值

// Get the value of the "phone" field and stuff it in a variable called phone
var phone = document.getElementById("phone").value;

// Set some values on a form using an array called response
document.getElementById("order").value = response[0];
document.getElementById("address").value = response[1];

這裏沒有特別需要注意的地方,真是好極了!您應該認識到這裏並沒有非常複雜的東西。只要掌握了 XMLHttpRequest,Ajax 應用程式的其他部分就是如 清單 2 所示的簡單 JavaScript 程式碼了,混合有少量的 HTML。同時,還要用一點 DOM,我們就來看看吧。

以 DOM 結束

最後還有 DOM,即文件物件模型。可能對有些讀者來說 DOM 有點令人生畏,HTML 設計者很少使用它,即使 JavaScript 程式設計師也不大用到它,除非要完成某項高層程式設計任務。大量使用 DOM 的是 複雜的 Java 和 C/C++ 程式,這可能就是 DOM 被認為難以學習的原因。

幸運的是,在 JavaScript 技術中使用 DOM 很容易,也非常直接。現在,按照常規也許應該說明如何使用 DOM,或者至少要給一些範例程式碼,但這樣做也可能誤導您。即使不理會 DOM,仍然能深入地探討 Ajax,這也是我準備採用的方法。以後的文章將再次討論 DOM,現在只要知道可能需要 DOM 就可以了。當需要在 JavaScript 程式碼和伺服器之間傳遞 XML 和改變 HTML 表單的時候,我們再深入研究 DOM。沒有它也能做一些有趣的工作,因此現在就把 DOM 放到一邊吧。

獲取 Request 對象

有了上面的基本知識後,我們來看看一些具體的例子。XMLHttpRequest 是 Ajax 應用程式的核心,而且對很多讀者來說可能還比較陌生,我們就從這裏開始吧。從 清單 1 可以看出,建立和使用這個物件非常簡單,不是嗎?等一等。

還記得幾年前的那些討厭的瀏覽器戰爭嗎?沒有一樣東西在不同的瀏覽器上得到同樣的結果。不管您是否相信,這些戰爭仍然在繼續,雖然規模較小。但令人奇怪的是,XMLHttpRequest 成了這場戰爭的犧牲品之一。因此獲得 XMLHttpRequest 物件可能需要採用不同的方法。下面我將詳細地進行解釋。

使用 Microsoft 瀏覽器

Microsoft 瀏覽器 Internet Explorer 使用 MSXML 解析器處理 XML。因此如果設計的 Ajax 應用程式要和 Internet Explorer 打交道,那麼必須用一種特殊的方式建立物件。但並不是這麼簡單。根據 Internet Explorer 中安裝的 JavaScript 技術版本不同,MSXML 實際上有兩種不同的版本,因此必須對這兩種情況分別設計程式碼。請參閱如下程式碼,其中的程式碼在 Microsoft 瀏覽器上建立了一個 XMLHttpRequest。

在 Microsoft 流覽器上創建 XMLHttpRequest 對象

var xmlHttp = false;
try {
  xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
  try {
    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
  } catch (e2) {
    xmlHttp = false;
  }
}
 

您對這些程式碼可能還不完全理解,但沒有關係。當本系列文章結束的時候,將對 JavaScript 程式設計、錯誤處理、條件編譯等有更深的瞭解。現在只要牢牢記住其中的兩行程式碼:

xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");

xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");。

這兩行程式碼基本上就是嘗試使用一個版本的 MSXML 建立物件,如果失敗則使用另一個版本建立該物件。如果不成功,則將 xmlHttp 變數設為 false,告訴您的程式碼出現了問題。如果出現這種情況,可能是因為安裝了非 Microsoft 瀏覽器,需要使用不同的程式碼。

處理 Mozilla 和非 Microsoft 瀏覽器

如果選擇的瀏覽器不是 Internet Explorer,或者為非 Microsoft 瀏覽器設計程式碼,就需要使用不同的程式碼。事實上就是 清單 1 所示的一行簡單程式碼:

var xmlHttp = new XMLHttpRequest object;。

這行簡單得多的程式碼在 Mozilla、Firefox、Safari、Opera 以及基本上所有以任何形式或方式支援 Ajax 的非 Microsoft 瀏覽器中,建立了 XMLHttpRequest 對象。關鍵是要支援所有瀏覽器。誰願意設計一個只能用於 Internet Explorer 或者非 Microsoft 瀏覽器的應用程式呢?或者更糟,要設計一個應用程式兩次?當然不!因此程式碼要同時支援 Internet Explorer 和非 Microsoft 瀏覽器。這樣的程式碼出現。

以支援多種瀏覽器的方式建立 XMLHttpRequest 物件

/* Create a new XMLHttpRequest object to talk to the Web server */
var xmlHttp = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try {
  xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
  try {
    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
  } catch (e2) {
    xmlHttp = false;
  }
}
@end @*/

if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
  xmlHttp = new XMLHttpRequest();
}

現在先不管那些注釋的奇怪符號,如 @cc_on,這是特殊的 JavaScript 編譯器命令。這段程式碼的核心分為三步:

  • 建立一個變數 xmlHttp 來引用即將建立的 XMLHttpRequest 對象。
  • 嘗試在 Microsoft 瀏覽器中建立該對象:
  • 嘗試使用 Msxml2.XMLHTTP 對象建立它。
  • 如果失敗,再嘗試 Microsoft.XMLHTTP 對象。
  • 如果仍然沒有建立 xmlHttp,則以非 Microsoft 的方式建立該物件。
  • 最後,xmlHttp 應該引用一個有效的 XMLHttpRequest 物件,無論運行什麼樣的瀏覽器。

關於安全性的一點說明

安全性如何呢?現在瀏覽器允許用戶提高他們的安全等級,關閉 JavaScript 技術,禁用瀏覽器中的任何選項。在這種情況下,程式碼無論如何都不會工作。現在要設計一段強健但不夠完美的程式碼,對於掌握 Ajax 來說就很好了。

Ajax 世界中的請求/回應

現在我們介紹了 Ajax,對 XMLHttpRequest 物件以及如何建立它也有了基本的瞭解。如果閱讀得很仔細,您可能已經知道與伺服器上的 Web 應用程式打交道的是 JavaScript 技術,而不是直接提交給那個應用程式的 HTML 表單。

還缺少什麼呢?到底如何使用 XMLHttpRequest。因為這段程式碼非常重要,您設計的每個 Ajax 應用程式都要以某種形式使用它,先看看 Ajax 的基本請求/回應模型是什麼樣吧。

發出請求

您已經有了一個嶄新的 XMLHttpRequest 物件,現在讓它幹點活兒吧。首先需要一個 Web 頁面能夠引用的 JavaScript 方法(比如當使用者輸入文字或者從功能表中選擇一項時)。接下來就是在所有 Ajax 應用程式中基本都雷同的流程:

  • 從 Web 表單中獲取需要的資料。
  • 建立要連接的 URL。
  • 打開到伺服器的連接。
  • 設置伺服器在完成後要執行的函數。
  • 發送請求。

如下的範例 Ajax 方法就是按照這個順序組織的:

發出 Ajax 請求

function callServer() {
  // Get the city and state from the web form
  var city = document.getElementById("city").value;
  var state = document.getElementById("state").value;
  // Only go on if there are values for both fields
  if ((city == null) || (city == "")) return;
  if ((state == null) || (state == "")) return;

  // Build the URL to connect to
  var url = "/scripts/getZipCode.php?city=" + escape(city) + "&state=" + escape(state);

  // Open a connection to the server
  xmlHttp.open("GET", url, true);

  // Setup a function for the server to run when it's done
  xmlHttp.onreadystatechange = updatePage;

  // Send the request
  xmlHttp.send(null);
}

開始的程式碼使用基本 JavaScript 程式碼獲取幾個表單字段的值。然後設置一個 PHP 腳本作為連結的目標。要注意腳本 URL 的指定方式,city 和 state 使用簡單的 GET 參數附加在 URL 之後。然後打開一個連接,這是您第一次看到使用 XMLHttpRequest。其中指定了連接方法(GET)和要連接的 URL。最後一個參數如果設為 true,那麼將請求一個非同步連接。如果使用 false,那麼程式碼發出請求後將等待伺服器返回的回應。如果設為 true,當伺服器在後臺處理請求的時候用戶仍然可以使用表單(甚至引用其他 JavaScript 方法)。xmlHttp 的 onreadystatechange 屬性可以告訴伺服器在執行完成後做什麼。因為程式碼沒有等待伺服器,必須讓伺服器知道怎麼做以便您能作出回應。在這個範例中,如果伺服器處理完了請求,一個特殊的名為 updatePage() 的方法將被觸發。最後,使用值 null 引用 send()。因為已經在請求 URL 中增加了要發送給伺服器的資料(city 和 state),所以請求中不需要傳送任何資料。這樣就發出了請求,伺服器按照您的要求工作。

如果沒有發現任何新鮮的東西,您應該體會到這是多麼簡單明瞭!除了牢牢記住 Ajax 的非同步特性外,這些內容都相當簡單。應該感激 Ajax 使您能夠專心設計漂亮的應用程式和介面,而不用擔心複雜的 HTTP 請求/回應程式碼。

程式碼說明了 Ajax 的易用性。資料是簡單的文字,可以作為請求 URL 的一部分。用 GET 而不是更複雜的 POST 發送請求。沒有 XML 和要增加的內容頭部,請求中沒有要傳送的資料。您將看到如何發送 POST 請求、如何設置請求頭部和內容類型、如何在訊息中設計 XML、如何增加請求的安全性,可以做的工作還有很多!暫時先不用管那些困難點,掌握好基本的東西就行了,很快我們就會建立一整套的 Ajax 工具庫。

處理回應

現在要面對伺服器的回應了。現在只要知道兩點:

什麼也不要做,直到 xmlHttp.readyState 屬性的值等於 4。
伺服器將把回應填寫到 xmlHttp.responseText 屬性中。

第一點,即就緒狀態。現在只要檢查一個特定的值(4)就可以了。
第二點,使用 xmlHttp.responseText 屬性獲得伺服器的回應。

處理伺服器回應

function updatePage() {
  if (xmlHttp.readyState == 4) {
    var response = xmlHttp.responseText;
    document.getElementById("zipCode").value = response;
  }
}

它等待伺服器調用,如果是就緒狀態,則使用伺服器返回的值(這裏是使用者輸入的城市和州的 ZIP 代碼)設置另一個表單字段的值。於是包含 ZIP 代碼的 zipCode 欄位突然出現了,而使用者沒有按任何按鈕!這就是前面所說的視窗應用程式的感覺。快速回應、動態感受等等,這些都只因為有了小小的一段 Ajax 程式碼。

細心的讀者可能注意到 zipCode 是一個普通的文字欄位。一旦伺服器傳回 ZIP 代碼,updatePage() 方法就用城市/州的 ZIP 代碼設置那個欄位的值,用戶就可以改寫該值。這樣做有兩個原因:保持例子簡單,說明有時候可能希望 用戶能夠修改伺服器返回的資料。要記住這兩點,它們對於好的用戶介面設計來說很重要。

連接 Web 表單

還有什麼呢?實際上沒有多少了。一個 JavaScript 方法獲取用戶輸入表單的資訊並將其發送到伺服器,另一個 JavaScript 方法監聽和處理回應,並在回應傳回時設置欄位的值。所有這些實際上都依賴於引用 第一個 JavaScript 方法,它啟動了整個過程。最明顯的辦法是在 HTML 表單中增加一個按鈕,但這是 2001 年的辦法,您不這樣認為嗎?還是像 清單 7 這樣利用 JavaScript 技術吧。

啟動一個 Ajax 過程

<form>
 <p>City: <input type="text" name="city" id="city" size="25"
       onChange="callServer();" /></p>
 <p>State: <input type="text" name="state" id="state" size="25"
       onChange="callServer();" /></p>
 <p>Zip Code: <input type="text" name="zipCode" id="city" size="5" /></p>
</form>

一段相當普通的程式碼。當用戶在 city 或 state 欄位中輸入新的值時,callServer() 方法就被觸發,於是 Ajax 開始執行了。

結束語

現在您可能已經準備開始設計第一個 Ajax 應用程式,但首先從這些應用程式如何工作的基本概念開始,對 XMLHttpRequest 物件有基本的瞭解,掌握這個物件,學會如何處理 JavaScript 和伺服器的通訊、如何使用 HTML 表單以及如何獲得 DOM 控制碼。

現在先花點時間考慮 Ajax 應用程式有多麼強大。設想一下,當點選按鈕、輸入一個欄位、從下拉式選單中選擇一個功能或者用滑鼠在螢幕上拖動時,Web 表單能夠立刻作出回應會是什麼情形。想一想非同步究竟意味著什麼,想一想 JavaScript 程式碼執行而且不等待伺服器對它的請求作出回應。會遇到什麼樣的問題?會進入什麼樣的領域?考慮到這種新的方法,程式設計的時候應如何改變表單的設計?

如果在這些問題上花一點時間,與簡單地剪下/貼上某些程式碼到您根本不理解的應用程式中相比,收益會更多。將把這些概念付諸實踐,使應用程式按照這種方式工作所需要的程式碼。因此,現在先享受一下 Ajax 所帶來的可能性吧。