AJAX 入門:第三個範例
The following examples had been tested on Mozilla's Firefox and Microsoft's IE. The document is provided as is. You are welcomed to use it for non-commercial purpose.Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu
請勿轉貼
在動態網頁設計的時候,我們經常需要依據使用者所選取的資料來決定 呈現的選項;例如,在本範例中,使用者可以選擇某個特定的城市,然後 網頁會依照使用者所選擇的城市來顯示使用者可以選擇的行政區;所以,如果 使用者選擇台中市的話,它只能選擇台中市的行政區,而不可能選到高雄市 的苓雅區。 要解決這樣的問題,傳統上都使用 DHTML 或者配合後端程式的使用來達成。 如果僅僅使用 DHTML 的方式來做,使用者會從伺服器端下載所有的城市,以及每一個 城市的行政區,這會造成大量的資料傳輸,非常不好。可是如果使用 後端程式的方式,使用者就必須像第一個範例中非 AJAX 網頁的情形,必須 每一次重新載入新資料都要等待(同步化的原因),非常不方便。所以,我們 就試著以 AJAX 的方式來解決。(範例無法在 Google 執行,請自行操作或者點選demo 網頁。)
請選擇適當的城市以及行政區:
說明:
- 設計 HTML 元件,其內容如下:
範例中的 form 被命名為 myform,這是因為我們需要利用 CSS/Javascript 的機制 來顯示或者隱藏某些 form 內的元件;經由命名為 myform,Javascript 就可以 利用 DOM 的機制快速的找到 form 元件。 myform 裡面包含兩個下拉式選單,分別命名為 city 和 areas。city 的下拉式 選單包含可以選擇的城市,範例中只有高雄以及台中;讀者可以一邊閱讀,一邊 將你喜歡的城市也加進去。至於行政區的標籤(即 id 為 label 的 div 區塊)以及其 下拉式選單(name 為 areas)並不需要顯示,這時候我們使用 CSS 的 display: none 和 display: inline 來處理;CSS 的設定如下:
<form name="myform"> 城市: <select name="city" onChange="display(document.myform.city.options[selectedIndex].text);"> <option value="none" selected="1">--</option> <option value="ks">高雄</option> <option value="chung">台中</option> </select><br/> <div id="label" class="off">行政區:</div> <select name="areas" class="off"> </select> </form>
在這個 CSS 中,我們設定了兩個 class selectors,分別為 on 和 off。由於 HTML 元件 label 和 areas 的 CSS 都設定為 off,當網頁載入的時候,使用者 並無法看到他們。 由於我們希望使用者選擇完了城市之後,AJAX 網頁能夠馬上依據使用者 選擇的城市,將該城市的行政區下載下來,並呈現在網頁上,我們必須為 city 下拉式選單設計一個事件處理器,該處理器需要在選單狀態改變的 時候執行,因此我們為 city 加上了 onChange 的屬性。如以上內容所示, 事件處理器命名為 display(),該處理器必須知道究竟是哪一個城市被選取, 而達成這個目標的 Javascript 物件為 document.myform.city.options[selectedIndex].text;其中,document.myform 會找到這個網頁中的 myform, 然後經由它找到 city;然後被選擇的城市可以經由 options[selectedIndex] 取得。取得之後,有兩種方式可以用來判斷,一種加上 .value,另一種是 加上 .text;例如,若使用者選擇台中,.value 回傳 "chung",而 .text 回傳"台中"。<style type="text/css"> .off { display: none } .on { display: inline } </style>
- 設計 display(str):由於 onChange 的時候,display() 會被呼叫,而且
城市的名稱會當作參數傳遞給 display()。所以,如果使用者選擇 "--",則
display() 只需要確保行政區的名稱(也就是 label)以及其下拉式選單 areas
不會出現,因此它們兩個必須如下的設定為 off:
反之,如果使用者選擇其他的城市,我們就必須像之前一樣,初始化 XMLHttpRequest 物件,然後將 url 設定好;也就是說,如果使用者 選擇高雄,url 為 ks.xml;若選擇台中,url 則為 taichung.xml。 這一段程式碼跟之前的重複性高,我們就不再多解釋。
if(str == '--') { document.getElementById('label').className = "off"; document.myform.areas.className = "off"; } - alertContents(http_request) 的設計:由於所有的行政區 XML 檔中,行政區
的名稱都是標籤名稱為 area 的文字節點(Text node),所以,程式中需要針對
這樣的結構把所有這樣的節點都找出來(也就是程式中 nodes 所代表);另外,
由於使用者可能選完台中之後,又選擇高雄,所以在把新的 nodes 的內容加到
current 節點(也就是代表下拉式選單 areas)之前,需要先把其內容刪除掉。
最後,程式就可以把新取得的行政區(也就是 nodes),利用 Javascript 的 DOM 方法(例如,document.createElement("option"))來產生必要的結果,其程式碼 如下:
var nodes = xmldoc.getElementsByTagName('area'); var current = document.myform.areas; // 使用者可能選完台中之後,又選擇高雄 // 如果有舊的 option,把它們清除掉 var anode, tnode; while(current.hasChildNodes()) { anode = current.firstChild; current.removeChild(anode); }在第 01 到 09 行的迴圈中,第 02 行先產生一個名為 option 的節點,這是因為 HTML 中下拉式選單(select)的子元素是 option;第 03 行為這個節點設定了 一個屬性名稱為 value,而屬性值為 i,而且(第 04-05 行中)如果這是第一個 option,則還為它加上一個 selected 的屬性;第 06 行將 option 這個節點成為 current 節點的子節點;第 07 行產生一個文字節點,內容為行政區的名稱; 第 08 行將這個文字節點變成 option 的子節點。 以台中為例,上述程式碼的第一個迴圈,所對應的節點變化如下表所示:01 for(var i=0; i<nodes.length; i++) { 02 anode = document.createElement("option"); 03 anode.setAttribute("value", i); 04 if(i == 0) 05 anode.setAttribute("selected", "1"); 06 current.appendChild(anode); 07 tnode = document.createTextNode(nodes[i].firstChild.data); 08 anode.appendChild(tnode); 09 }
行 數 HTML 節點 新節點 第 02 行 <select>
</select><option/> 第 03 行 <select>
</select><option value="0"/> 第 04-05 行 <select>
</select><option value="0" selected="1"/> 第 06 行 <select>
<option value="0" selected="1"/>
</select>加到 HTML 後就不在這裡顯示,避免變得太複雜。 第 07 行 <select>
<option value="0" selected="1"/>
</select>中區 (綠色代表文字節點) 第 08 行 <select>
<option value="0" selected="1">中區</option>
</select> - 完整的程式碼如下:
<script language="javascript"> <!-- function display(str) { if(str == '--') { document.getElementById('label').className = "off"; document.myform.areas.className = "off"; } else { // insert AJAX code here var http_request = false; if(window.XMLHttpRequest) { // Mozilla, Safari, .... http_request = new XMLHttpRequest(); } 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; } // 定義事件處理函數為 alterContents() http_request.onreadystatechange = function() { alertContents(http_request); }; if(str == '高雄') { url = 'ks.xml'; } else { url = 'taichung.xml'; } http_request.open('GET', url, true); http_request.send(null); } } function alertContents(http_request) { if (http_request.readyState == 4) { if (http_request.status == 200) { var xmldoc = http_request.responseXML; var nodes = xmldoc.getElementsByTagName('area'); var current = document.myform.areas; var anode, tnode; while(current.hasChildNodes()) { anode = current.firstChild; current.removeChild(anode); } for(var i=0; i<nodes.length; i++) { anode = document.createElement("option"); anode.setAttribute("value", i); if(i == 0) anode.setAttribute("selected", "1"); current.appendChild(anode); tnode = document.createTextNode(nodes[i].firstChild.data); anode.appendChild(tnode); } document.getElementById('label').className = "on"; document.myform.areas.className = "on"; } else { alert('There was a problem with the request.'); } } } // --> </script> - 練習題: 請依據本範例,設計一對下拉式選單;第一個下拉式選單出現 產品分類(例如:3C 產品、時尚流行等),當選擇第一個選單項目之後,會出現 該產品分類的產品(例如,若使用者選擇 "3C 產品",則出現個人電腦、筆電、 平板電腦等產品)。
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu
沒有留言:
張貼留言