用傳統方式校驗用戶名是否重復
傳統方式校驗用戶名是否重復的設計分析
RegUserUI
Reguser.jsp
RegUser
Main.jsp
注冊
校驗用戶名
是否重復
VerifyUserName
?返回怎樣的
一個頁面
VerifyUserName這個Action校驗用戶名后還要回到第一個jsp頁面上,而第一個jsp頁面是第一個action顯示出來的,所以也可以在第一個action的基礎上增加校驗用戶名的功能,這就沒有做到職責單一了,思路沒有單獨做一個VerifyUserName的action來校驗用戶名清晰。
在校驗用戶名的action和jsp頁面中要增加怎樣的代碼呢?由於顯示結果是增加一條提示信息而已(用<div>將提示信息包起來, 有信息時顯示信息,沒信息時保持空白),所以在action中也就是要增加一條存儲提示信息的代碼,寫完action后,問題就是jsp頁面上如何實現將校驗用戶名是否存在的請求及參數提交給第一個action了,這時候必須寫javascript函數了,並應掌握<html:rewrite>標簽和document.location.href屬性。
傳統實現方式1 :在原來的主窗口中回顯結果
問題:
1:回顯的頁面在原來網頁效果的基礎上增加一點內容,可是服務器的響應結果會覆蓋掉窗口中原來顯示的那個網頁內容,如果服務器在響應時僅僅回送要新增的內容,則會覆蓋掉原來的整個網頁,怎樣做才能看到原來網頁效果的基礎上增加一點內容?
2:怎樣用javascript代碼將請求發送給服務器,在發送請求時,怎樣將文本框中填寫的用戶名作為參數傳遞給服務器。
3:怎樣在<a>標簽中觸發javascript函數調用?觸發函數時要注意返回值。
實現思路:
讓VerifyUserName仍然返回Reguser.jsp,這時候需要在Reguser.jsp頁面中增加一條有時候顯示,有時候不顯示的提示信息。或者是通過生成一段javascript代碼,然后用一個彈出對話框來顯示提示信息。先用瀏覽器直接測試 VerifyUserName。
在<a>標簽中可以使用javascript協議或onclick事件來觸發javascript函數調用,先用靜態數據測試一下,然后用window.location.href屬性(replace方法)或模擬表單提交的方式向服務器發送請求,把兩種方式都要做一下。
缺點:
要為電腦增加一個鼠標,由於瀏覽器的特點是買回鼠標就會覆蓋掉原來的電腦,所以,要想顯示出電腦加鼠標的效果,只能同時去買回一個電腦和鼠標。
好比舞台要切換帷幕一樣,上一場的帷幕上貼的是花,當下一場要換成貼龍時,最快的方式不是把原來帷幕上的花揭下來再換上龍,而是做兩個帷幕,直接把上一個帷幕收起,同時把下一個帷幕拉開。每次都送出一個帷幕,帷幕上貼不同內容。
<html:base> 標簽會害你的,例如,它生成的路徑<base href=“http://localhost:8080/ajaxdemo/WEB-INF/user/RegUser.jsp”>,我們網頁中的相對路徑全變成/Web-inf/user下面的了。雖然我在課堂上提前講了,但在練習時,很多同學還是都犯了這個錯誤並找不出原因來。
講超鏈接的javascript協議時,先用這個代碼說一下:<a href=“javascript:3”></a>,讓大家明白返回值的而影響,也可以直接在瀏覽器地址欄輸入javascript:window.document,瀏覽器將顯示[object]。
對於onclick的講解:
1.在保留<html:base/>標簽時,用用<a href=‘<html:rewrite action=“#’ onclick=”verifyUserName()“>做,看到<html:base/>標簽導致的錯誤后果。照理說,超鏈接這里用# 不應該發送請求的,但我把jsp頁面放在web-inf里時,瀏覽器要發請求,有同學沒放在web-inf里,結果沒發請求。
2.去掉<html:base/> 標簽,看到正確的效果后,
3.增加超鏈接,將#改為空白,即改成如下形式:
<a href=“” onclick=“verifyUserName()”>校驗用戶名是否存在</a>
在這里說明清楚了如果不返回false,除了干事件處理代碼,還干原來默認的行為,關於如果取消原來的行為,看完下面的實驗后繼續講解。
4.增加超鏈接,讓路徑指向VerifyUserName,
<a href='<html:rewrite action="/VerifyUserName"/>' onclick="verifyUserName()">校驗用戶名是否存在</a>
這時候,即使用戶名為zxx,也說沒有重復,這是因為瀏覽器除了訪問javascript中設置的VerifyUserName這個地址外,還執行了超鏈接原來的行為,又根據href的值再次發出了請求,一共發了兩次請求,瀏覽器顯示了后面的請求的結果。
5.通過3步和第4步的問題,引出了事件處理函數中的return false的作用,可以通過這個代碼輔助說明:<a href="delAction?id=3" onclick="return confirm('真的嗎?')">刪除</a>
var url = '<html:rewrite action="/AjaxVerifyUserName?username="/>' + userName;
上面的為什么要用單引號引起來才成為javascript的字符串,否則會當作變量處理,課堂上專門演示和說明了,練習時還有同學犯這個錯誤,我覺得關鍵是要告訴大家是檢查javascript代碼時,不能在jsp頁面檢查,而應該在其生成的網頁內容中檢查。做bs的界面時,最終的效果是瀏覽器顯示網頁而造成的,如果界面有問題,首先要查網頁的源代碼找出問題,然后才能推斷出jsp在生成網頁源代碼時出現了什么問題,這對於很多人來說都不知道。
對於第2個問題:javascript是一種對它所在的網頁文檔及網頁上的各個元素進行操作的語言,即可以對網頁上的文本框進行增刪改查,現在要獲取用戶名文本框中的內容,你說怎么辦?
預備的實驗內容:
<form>
用戶名:<input type="text" name="username" /><br>
密碼:<input type="password" name="password" /><br>
確認密碼:<input type="password" name="password2" /><br>
<input type="submit" value="注冊"/>
</form>
校驗用戶名是否存在
恭喜你,用戶名未被注冊!
很遺憾,用戶名已被注冊!
傳統實現方式2 :用彈出的新窗口回顯結果
實現方式:在彈出窗口中回顯結果
彈出窗口演示
模態對話框演示
實現思路:
由彈出窗口打開一個網頁的方式發出校驗用戶名的請求,回送的應該是一個網頁,只是這個網頁的內容很簡單,但是,如果要有關閉按鈕,必須加上相應的按鈕和javascript代碼。
模態對話框的好處在於避免了受瀏覽器顯示新窗口的方式的差異的影響,並可要求用戶必須關閉彈出窗口后才能進行其他操作。
特點:
服務器回送的結果給新窗口,不影響原始窗口。一個帷幕收起,同時把下一個帷幕拉開。每次都送出一個帷幕,帷幕上貼不同內容。
<html:base> 標簽會害你的,例如,它生成的路徑<base href=“http://localhost:8080/ajaxdemo/WEB-INF/user/RegUser.jsp”>,我們網頁中的相對路徑全變成/Web-inf/user下面的了。雖然我在課堂上提前講了,但在練習時,很多同學還是都犯了這個錯誤並找不出原因來。
講超鏈接的javascript協議時,先用這個代碼說一下:<a href=“javascript:3”></a>,讓大家明白返回值的而影響,也可以直接在瀏覽器地址欄輸入javascript:window.document,瀏覽器將顯示[object]。
對於onclick的講解:
1.在保留<html:base/>標簽時,用用<a href=‘<html:rewrite action=“#’ onclick=”verifyUserName()“>做,看到<html:base/>標簽導致的錯誤后果。照理說,超鏈接這里用# 不應該發送請求的,但我把jsp頁面放在web-inf里時,瀏覽器要發請求,有同學沒放在web-inf里,結果沒發請求。
2.去掉<html:base/> 標簽,看到正確的效果后,
3.增加超鏈接,將#改為空白,即改成如下形式:
<a href=“” onclick=“verifyUserName()”>校驗用戶名是否存在</a>
在這里說明清楚了如果不返回false,除了干事件處理代碼,還干原來默認的行為,關於如果取消原來的行為,看完下面的實驗后繼續講解。
4.增加超鏈接,讓路徑指向VerifyUserName,
<a href='<html:rewrite action="/VerifyUserName"/>' onclick="verifyUserName()">校驗用戶名是否存在</a>
這時候,即使用戶名為zxx,也說沒有重復,這是因為瀏覽器除了訪問javascript中設置的VerifyUserName這個地址外,還執行了超鏈接原來的行為,又根據href的值再次發出了請求,一共發了兩次請求,瀏覽器顯示了后面的請求的結果。
5.通過3步和第4步的問題,引出了事件處理函數中的return false的作用,可以通過這個代碼輔助說明:<a href="delAction?id=3" onclick="return confirm('真的嗎?')">刪除</a>
var url = '<html:rewrite action="/AjaxVerifyUserName?username="/>' + userName;
上面的為什么要用單引號引起來才成為javascript的字符串,否則會當作變量處理,課堂上專門演示和說明了,練習時還有同學犯這個錯誤,我覺得關鍵是要告訴大家是檢查javascript代碼時,不能在jsp頁面檢查,而應該在其生成的網頁內容中檢查。做bs的界面時,最終的效果是瀏覽器顯示網頁而造成的,如果界面有問題,首先要查網頁的源代碼找出問題,然后才能推斷出jsp在生成網頁源代碼時出現了什么問題,這對於很多人來說都不知道。
對於第2個問題:javascript是一種對它所在的網頁文檔及網頁上的各個元素進行操作的語言,即可以對網頁上的文本框進行增刪改查,現在要獲取用戶名文本框中的內容,你說怎么辦?
預備的實驗內容:
<form>
用戶名:<input type="text" name="username" /><br>
密碼:<input type="password" name="password" /><br>
確認密碼:<input type="password" name="password2" /><br>
<input type="submit" value="注冊"/>
</form>
校驗用戶名是否存在
恭喜你,用戶名未被注冊!
很遺憾,用戶名已被注冊!
Ajax的概念:
是asynchronous javascript and xml的簡寫。
不是一項具體的技術,而是幾門技術的綜合應用。
其核心只不過是要在javascript中調用一個叫XMLHttpRequest的javascript類,這個類可以與Web服務器使用HTTP協議進行交互,程序不通過瀏覽器發出請求,而是用這個特殊的JavaScript對象發送請求,再由這個JavaScript對象接收響應,並將響應結果用DOM編程方式掛到原來的網頁上(見下頁的圖),從而使得javascript借助這個api類可以干出比較有意義的事情。
XMLHttpRequest對象在網絡上的俗稱為XHR對象。
Ajax的特點:
瀏覽器中顯示一個頁面后,這個頁面以后一直不改變,所有的操作請求都由這個網頁中的javascript代碼發出,所有的結果都由javascript代碼接受並增加到這個頁面上,瀏覽器窗口中顯示的網頁始終都是初始的那個網頁。(見下面兩頁的圖)
增強用戶體驗:可以在用戶瀏覽網頁的同時與服務器進行異步交互和實現網頁內容的局部更新,例如,126郵箱密碼安全性判斷和google suggest;可以按需取數據,改善頁面顯示速度,例如,樹狀菜單和babasport的首頁(整合多個信息的頁面);視覺流暢的定時刷新,例如,聊天室。(用下幾頁的圖舉例說明)
學習ajax和應用ajax的難點不在於XMLHttpRequest本身,而在於javascript和DOM編程,沒有較好的javascript和DOM編程基礎,你就很難做出有意義的ajax應用。
瀏覽器的普通交互方式
Ajax的交互方式
同步交互和異步交互
舉個例子:普通B/S模式(同步) AJAX技術(異步)
* 同步:提交請求->等待服務器處理->處理完畢返回 這個期間客戶端瀏覽器不能干任何事
* 異步: 請求通過事件觸發->服務器處理(這時瀏覽器仍然可以作其他事情)->處理完畢
同步是指:發送方發出數據后,等接收方發回響應以后才發下一個
數據包的通訊方式。
異步是指:發送方發出數據后,不等接收方發回響應,接着發送下
個數據包的通訊方式
易懂的理解:
異步傳輸: 你傳輸吧,我去做我的事了,傳輸完了告訴我一聲
同步傳輸: 你現在傳輸,我要親眼看你傳輸完成,才去做別的事
AJAX案例之google suggest
AJAX案例之Google Maps
Ajax的應用場景:財富通網吧充值界面
Ajax的應用場景:密碼安全性檢測
Ajax的應用場景:RIA應用
Ajax的應用場景:郵箱系統
Ajax的應用場景:藍源批發零售業連鎖管理系統
究竟什么是Ajax
Ajax:一種不用刷新整個頁面便可與服務器通訊的辦法
圖1 Web的傳統模型。客戶端向服務器發送一個請求,服務器返回整個頁面,如此反復
圖2 在Ajax模型中,數據在客戶端與服務器之間獨立傳輸。服務器不再返回整個頁面
Ajax的實現方式
不用刷新整個頁面便可與服務器通訊的辦法:
Flash
Java applet
框架:如果使用一組框架構造了一個網頁,可以只更新其中一個框架,而不必驚動整個頁面
隱藏的iframe
XMLHttpRequest:該對象是對 JavaScript 的一個擴展,可使網頁與服務器進行通信。是創建 Ajax 應用的最佳選擇。實際上通常把 Ajax 當成 XMLHttpRequest 對象的代名詞
Ajax的工作原理
Ajax的核心是JavaScript對象XmlHttpRequest。
該對象在Internet Explorer 5中首次引入,它是一種支持異步請求的技術。簡而言之,XmlHttpRequest使您可以使用JavaScript向服務器提出請求並處理響應,而不阻塞用戶。
AJAX采用異步交互過程。AJAX在用戶與服務器之間引入一個中間媒介,從而消除了網絡交互過程中的處理—等待—處理—等待缺點。
用戶的瀏覽器在執行任務時即裝載了AJAX引擎。AJAX引擎用JavaScript語言編寫,通常藏在一個隱藏的框架中。它負責編譯用戶界面及與服務器之間的交互。
AJAX引擎允許用戶與應用軟件之間的交互過程異步進行,獨立於用戶與網絡服務器間的交流。現在,可以用Javascript調用AJAX引擎來代替產生一個HTTP的用戶動作,內存中的數據編輯、頁面導航、數據校驗這些不需要重新載入整個頁面的需求可以交給AJAX來執行。
使用AJAX,可以為JSP、開發人員、終端用戶帶來可見的便捷:
用戶界面
AJAX引擎
服務器
用戶界面
服務器
AJAX包含的技術
AJAX:(Asynchronous JavaScript and XML)並不是一項新技術,其實是多種技術的綜合,包括Javascript、XHTML和CSS、DOM、XML和XMLHttpRequest.
服務器端語言:服務器需要具備向瀏覽器發送特定信息的能力。Ajax與服務器端語言無關。
XML (eXtensible Markup Language,可擴展標記語言) 是一種描述數據的格式。AJAX 程序需要某種格式化的格式來在服務器和客戶端之間傳遞信息,XML 是其中的一種選擇
XHTML(eXtended Hypertext Markup Language,使用擴展超媒體標記語言)和 CSS(Cascading Style Sheet,級聯樣式單)標准化呈現;
DOM(Document Object Model,文檔對象模型)實現動態顯示和交互;
使用XMLHTTP組件XMLHttpRequest對象進行異步數據讀取
使用JavaScript綁定和處理所有數據
AJAX的缺陷
AJAX不是完美的技術。也存在缺陷:
1 AJAX大量使用了Javascript和AJAX引擎,而這個取決於瀏覽器的支持。IE5.0及以上、Mozilla1.0、NetScape7及以上版本才支持,Mozilla雖然也支持AJAX,但是提供XMLHttpRequest的方式不一樣。所以,使用AJAX的程序必須測試針對各個瀏覽器的兼容性。
2 AJAX更新頁面內容的時候並沒有刷新整個頁面,因此,網頁的后退功能是失效的;有的用戶還經常搞不清楚現在的數據是舊的還是已經更新過的。這個就需要在明顯位置提醒用戶“數據已更新”。
3 對流媒體的支持沒有FLASH、Java Applet好。
4 一些手持設備(如手機、PDA等)現在還不能很好的支持Ajax。
XMLHttpRequest對象
XMLHttpRequest是XMLHTTP組件的對象,通過這個對象,AJAX可以像桌面應用程序一樣只同服務器進行數據層面的交換,而不用每次都刷新界面,也不用每次將數據處理的工作都交給服務器來做;這樣既減輕了服務器負擔又加快了響應速度、縮短了用戶等待的時間。
XMLHttpRequest最早是在IE5中以ActiveX組件的形式實現的。非W3C標准.
創建XMLHttpRequest對象(由於非標准所以實現方法不統一)
Internet Explorer把XMLHttpRequest實現為一個ActiveX對象
其他瀏覽器(Firefox、Safari、Opera…)把它實現為一個本地的JavaScript對象。
XMLHttpRequest在不同瀏覽器上的實現是兼容的,所以可以用同樣的方式訪問XMLHttpRequest實例的屬性和方法,而不論這個實例創建的方法是什么。
XMLHttpRequest對象初始化
function createXmlHttpRequest(){
var xmlhttp = null;
try{
//Firefox, Opera 8.0+, Safari
xmlhttp=new XMLHttpRequest();
}catch(e){//IEIE7.0以下的瀏覽器以ActiveX組件的方式來創建XMLHttpRequest對象
var MSXML =
['MSXML2.XMLHTTP.6.0','MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0','MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP','Microsoft.XMLHTTP'];
for(var n = 0; n < MSXML.length; n ++){
try{
xmlhttp = new ActiveXObject(MSXML[n]);
break;
}catch(e){}}
}
return xmlhttp;
}
XMLHttpRequest對象方法
| 方法 |
描述 |
| abort() |
停止當前請求 |
| getAllResponseHeaders() |
把http請求的所有響應首部作為鍵/值對返回 |
| getResponseHeader("headerLabel") |
返回指定首部的串值 |
| open(“method”,”url”) |
建立對服務器的調用,method參數可以是GET,POST。url參數可以是相對URL或絕對URL。這個方法還包括3個可選參數。 |
| send(content) |
向服務器發送請求 |
| setRequestHeader("label", "value") |
把指定首部設置為所提供的值。在設置任何首部之前必須先調用open() |
XMLHttpRequest對象屬性
發送請求--方法和屬性介紹
利用XMLHttpRequest 實例與服務器進行通信包含以下3個關鍵部分:
onreadystatechange 事件處理函數
open 方法
send 方法
onreadystatechange:
該事件處理函數由服務器觸發,而不是用戶
在 Ajax 執行過程中,服務器會通知客戶端當前的通信狀態。這依靠更新 XMLHttpRequest 對象的 readyState 來實現。改變 readyState 屬性是服務器對客戶端連接操作的一種方式。
每次 readyState 屬性的改變都會觸發 readystatechange事件
open(method, url, asynch)
XMLHttpRequest 對象的 open 方法允許程序員用一個Ajax調用向服務器發送請求。
method:請求類型,類似 “GET”或”POST”的字符串。若只想從服務器檢索一個文件,而不需要發送任何數據,使用GET(可以在GET請求里通過附加在URL上的查詢字符串來發送數據,不過數據大小限制為2000個字符)。若需要向服務器發送數據,用POST。
在某些情況下,有些瀏覽器會把多個XMLHttpRequest請求的結果緩存在同一個URL。如果對每個請求的響應不同,這就會帶來不好的結果。把當前時間戳追加到URL的最后,就能確保URL的惟一性,從而避免瀏覽器緩存結果。
url:路徑字符串,指向你所請求的服務器上的那個文件。可以是絕對路徑或相對路徑。
asynch:表示請求是否要異步傳輸,默認值為true(異步)。指定true,在讀取后面的腳本之前,不需要等待服務器的相應。指定false,當腳本處理過程經過這點時,會停下來,一直等到Ajax請求執行完畢再繼續執行。
var url = "GetAndPostExample?timeStamp=" + new Date().getTime();
send(data):
open 方法定義了 Ajax 請求的一些細節。send 方法可為已經待命的請求發送指令
data:將要傳遞給服務器的字符串。
若選用的是 GET 請求,則不會發送任何數據, 給 send 方法傳遞 null 即可:request.send(null);
當向send()方法提供參數時,要確保open()中指定的方法是POST,如果沒有數據作為請求體的一部分發送,則使用null.
完整的 Ajax 的 GET 請求示例:
使用get請求時send方法參數時null,如果傳值的話,服務器也接受不到
setRequestHeader(header,value)
當瀏覽器向服務器請求頁面時,它會伴隨這個請求發送一組首部信息。這些首部信息是一系列描述請求的元數據(metadata)。首部信息用來聲明一個請求是 GET 還是 POST。
Ajax 請求中,發送首部信息的工作可以由 setRequestHeader完成
參數header: 首部的名字; 參數value:首部的值。
如果用 POST 請求向服務器發送數據,需要將 “Content-type” 的首部設置為 “application/x-www-form-urlencoded”.它會告知服務器正在發送數據,並且數據已經符合URL編碼了。
該方法必須在open()之后才能調用
完整的 Ajax 的 POST 請求示例:
用 XMLHttpRequest 的方法可向服務器發送請求。在 Ajax 處理過程中,XMLHttpRequest 的如下屬性可被服務器更改:
readyState
status
responseText
responseXML
readyState
readyState 屬性表示Ajax請求的當前狀態。它的值用數字代表。
0 代表未初始化。 還沒有調用 open 方法
1 代表正在加載。 open 方法已被調用,但 send 方法還沒有被調用
2 代表已加載完畢。send 已被調用。請求已經開始
3 代表交互中。服務器正在發送響應
4 代表完成。響應發送完畢
每次 readyState 值的改變,都會觸發 readystatechange 事件。如果把 onreadystatechange 事件處理函數賦給一個函數,那么每次 readyState 值的改變都會引發該函數的執行。
readyState 值的變化會因瀏覽器的不同而有所差異。但是,當請求結束的時候,每個瀏覽器都會把 readyState 的值統一設為 4
status
服務器發送的每一個響應也都帶有首部信息。三位數的狀態碼是服務器發送的響應中最重要的首部信息,並且屬於超文本傳輸協議中的一部分。
常用狀態碼及其含義:
404 沒找到頁面(not found)
403 禁止訪問(forbidden)
500 內部服務器出錯(internal service error)
200 一切正常(ok)
304 沒有被修改(not modified)(服務器返回304狀態,表示源文件沒有被修改 )
在 XMLHttpRequest 對象中,服務器發送的狀態碼都保存在 status 屬性里。通過把這個值和 200 或 304 比較,可以確保服務器是否已發送了一個成功的響應
responseText
XMLHttpRequest 的 responseText 屬性包含了從服務器發送的數據。它是一個HTML,XML或普通文本,這取決於服務器發送的內容。
當 readyState 屬性值變成 4 時, responseText 屬性才可用,表明 Ajax 請求已經結束。
responseXML
如果服務器返回的是 XML, 那么數據將儲存在 responseXML 屬性中。
只用服務器發送了帶有正確首部信息的數據時, responseXML 屬性才是可用的。 MIME 類型必須為 text/xml
AJAX開發框架
AJAX實質上也是遵循Request/Server模式,所以這個框架基本的流程是:
對象初始化
發送請求
服務器接收
服務器返回
客戶端接收
修改客戶端頁面內容。
只不過這個過程是異步的。
A、初始化XMLHttpRequest對象
function createXmlHttpRequest(){
var xmlhttp = null;
try{
//Firefox, Opera 8.0+, Safari
xmlhttp=new XMLHttpRequest();
}catch(e){//IEIE7.0以下的瀏覽器以ActiveX組件的方式來創建XMLHttpRequest對象
var MSXML =
['MSXML2.XMLHTTP.6.0','MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0','MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP','Microsoft.XMLHTTP'];
for(var n = 0; n < MSXML.length; n ++){
try{
xmlhttp = new ActiveXObject(MSXML[n]);
break;
}catch(e){}}
}
return xmlhttp;
}
B、指定響應處理函數
指定當服務器返回信息時客戶端的處理方式。只要將相應的處理函數名稱賦給XMLHttpRequest對象的onreadystatechange屬性就可以了.比如:
XMLHttpReq.onreadystatechange = processResponse;
注意:這個函數名稱不加括號,不指定參數。也可以用Javascript函數直接量方式定義響應函數。比如:
XMLHttpReq.onreadystatechange = function() { };
// 處理返回信息的函數
function processResponse() {
}
C、發出HTTP請求
向服務器發出HTTP請求了。這一步調用XMLHttpRequest對象的open和send方法。
http_request.open('GET', 'http://www.example.org/some.file', true);
http_request.send(null)
按照順序,open調用完畢之后要調用send方法。send的參數如果是以Post方式發出的話,可以是任何想傳給服務器的內容。
注意:如果要傳文件或者Post內容給服務器,必須先調用setRequestHeader方法,修改MIME類別。如下:
http_request.setRequestHeader(“Content-Type”,”application/x-www-form-urlencoded”);
這時資料則以查詢字符串的形式列出,作為send的參數,例如:
name=value&anothername=othervalue&so=on
發出Http請求的代碼
//發送請求
function sendRequest(){
//獲取文本框的值
var chatMsg=input.value;
var url="chatServlet.do?charMsg="+chatMsg;
//建立對服務器的調用
XMLHttpReq.open("POST",url,true);
//設置MiME類別,如果用 POST 請求向服務器發送數據,
//需要將"Content-type" 的首部設置為 "application/x-www-form-urlencoded".
//它會告知服務器正在發送數據,並且數據已經符合URL編碼了。
XMLHttpReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//狀態改變的事件觸發器,客戶端的狀態改變會觸發readystatechange事件,
//onreadystatechange會調用相應的事件處理函數
XMLHttpReq.onreadystatechange=processResponse;
//發送數據
XMLHttpReq.send(null);
}
D、處理服務器返回的信息
處理響應處理函數都應該做什么。
首先,它要檢查XMLHttpRequest對象的readyState值,判斷請求目前的狀態。參照前文的屬性表可以知道,readyState值為4的時候,代表服務器已經傳回所有的信息,可以開始處理信息並更新頁面內容了。如下:
if (http_request.readyState == 4) {
// 信息已經返回,可以開始處理
} else {
// 信息還沒有返回,等待
}
服務器返回信息后,還需要判斷返回的HTTP狀態碼,確定返回的頁面沒有錯誤。所有的狀態碼都可以在W3C的官方網站上查到。其中,200代表頁面正常。
if (http_request.status == 200) {
// 頁面正常,可以開始處理信息
} else {
// 頁面有問題
}
XMLHttpRequest對成功返回的信息有兩種處理方式:
responseText:將傳回的信息當字符串使用;
responseXML:將傳回的信息當XML文檔使用,可以用DOM處理。
//處理返回信息的函數
function processResponse(){
if(XMLHttpReq.readyState==4){ //判斷對象狀態 4代表完成
if(XMLHttpReq.status==200){ //信息已經成功返回,開始處理信息
document.getElementById("chatArea").value=XMLHttpReq.responseText;
}
}
}
數據格式摘要
在服務器端 AJAX 是一門與語言無關的技術。在業務邏輯層使用何種服務器端語言都可以。
從服務器端接收數據的時候,那些數據必須以瀏覽器能夠理解的格式來發送。服務器端的編程語言一般以如下 3 種格式返回數據:
XML
JSON
HTML
XML格式
優點:
XML 是一種通用的數據格式。
不必把數據強加到已定義好的格式中,而是要為數據自定義合適的標記。
利用 DOM 可以完全掌控文檔。
缺點:
如果文檔來自於服務器,就必須得保證文檔含有正確的首部信息。若文檔類型不正確,那么 responseXML 的值將是空的。
當瀏覽器接收到長的 XML 文件后, DOM 解析可能會很復雜
JSON格式
JSON(JavaScript Object Notation)一種簡單的數據格式,比xml更輕巧。JSON是JavaScript原生格式,這意味着在JavaScript中處理JSON數據不需要任何特殊的API或工具包。
JSON的規則很簡單:對象是一個無序的“‘名稱/值’對”集合。一個對象以“{”(左括號)開始,“}”(右括號)結束。每個“名稱”后跟一個“:”(冒號);“‘名稱/值’對”之間使用“,”(逗號)分隔。
規則如下:
1)映射用冒號(“:”)表示。名稱:值
2)並列的數據之間用逗號(“,”)分隔。名稱1:值1,名稱2:值2
3) 映射的集合(對象)用大括號(“{}”)表示。{名稱1:值1,名稱2:值2}
4) 並列數據的集合(數組)用方括號(“[]”)表示。
[
{名稱1:值,名稱2:值2},
{名稱1:值,名稱2:值2}
]
5 元素值可具有的類型:string, number, object, array, true, false, null
JSON 示例
JSON 用冒號(而不是等號)來賦值。每一條賦值語句用逗號分開。整個對象用大括號封裝起來。可用大括號分級嵌套數據。
對象描述中存儲的數據可以是字符串,數字或者布爾值。對象描述也可存儲函數,那就是對象的方法。
解析JSON
JSON 只是一種文本字符串。它被存儲在 responseText 屬性中
為了讀取存儲在 responseText 屬性中的 JSON 數據,需要根據 JavaScript 的 eval 語句。函數 eval 會把一個字符串當作它的參數。然后這個字符串會被當作 JavaScript 代碼來執行。因為 JSON 的字符串就是由 JavaScript 代碼構成的,所以它本身是可執行的
代碼實例:
處理JSON
例子一:
<script language="JavaScript">
var people ={"firstName": "Brett", "lastName":"McLaughlin",
"email": "brett@newInstance.com" };
alert(people.firstName);
alert(people.lastName);
alert(people.email);
</script>
例子二:
<script language="JavaScript">
var people =[
{"firstName": "Brett","email": "brett@newInstance.com" },
{"firstName": "Mary","email": "mary@newInstance.com" }
];
alert(people[0].firstName);
alert(people[0].email);
alert(people[1].firstName);
alert(people[1].email);
</script>
例子三:
<script language="JavaScript">
var people ={
"programmers":
[
{"firstName": "Brett", "email": "brett@newInstance.com" },
{"firstName": "Jason", "email": "jason@servlets.com" }
]
};
window.alert(people.programmers[0].firstName);
window.alert(people.programmers[1].email);
</script>
例子四:
<script language="JavaScript">
var people ={
"programmers": [
{ "firstName": "Brett", "email": "brett@newInstance.com" },
{ "firstName": "Jason", "email": "jason@servlets.com" },
{ "firstName": "Elliotte", "lastName":"Harold", "email": "elharo@macfaq.com" }
],
"authors": [
{ "firstName": "Isaac", "genre": "science fiction" },
{ "firstName": "Tad", "genre": "fantasy" },
{ "firstName": "Frank", "genre": "christian fiction" }
],
"musicians": [
{ "firstName": "Eric", "instrument": "guitar" },
{ "firstName": "Sergei", "instrument": "piano" }
]};
window.alert(people.programmers[1].firstName);
window.alert(people.musicians[1].instrument);
</script>
例子五
<script language="JavaScript">
var people ={
"username":"mary",
"age":"20",
"info":{"tel":"1234566","celltelphone":788666},
"address":[
{"city":"beijing","code":"1000022"},
{"city":"shanghai","code":"2210444"}
]
};
window.alert(people.username);
window.alert(people.info.tel);
window.alert(people.address[0].city);
</script>
JSON 小結
優點:
作為一種數據傳輸格式,JSON 與 XML 很相似,但是它更加靈巧。
JSON 不需要從服務器端發送含有特定內容類型的首部信息。
缺點:
語法過於嚴謹
代碼不易讀
eval 函數存在風險
解析 HTML
HTML 由一些普通文本組成。如果服務器通過 XMLHttpRequest 發送 HTML, 文本將存儲在 responseText 屬性中。
不必從 responseText 屬性中讀取數據。它已經是希望的格式,可以直接將它插入到頁面中。
插入 HTML 代碼最簡單的方法是更新這個元素的 innerHTML 屬性。
HTML 小結
優點:
從服務器端發送的 HTML 代碼在瀏覽器端不需要用 JavaScript 進行解析。
HTML 的可讀性好。
HTML 代碼塊與 innerHTML 屬性搭配,效率高。
缺點:
若需要通過 AJAX 更新一篇文檔的多個部分,HTML 不合適
innerHTML 並非 DOM 標准。
對比小結
若應用程序不需要與其他應用程序共享數據的時候, 使用 HTML 片段來返回數據時最簡單的
如果數據需要重用, JSON 文件是個不錯的選擇, 其在性能和文件大小方面有優勢
當遠程應用程序未知時, XML 文檔是首選, 因為 XML 是 web 服務領域的 “世界語”
案例:省份與城市的聯動下拉列表框
效果演示。
聯動下拉:純靜態數據的html方式
實驗步驟:
演示程序運行的效果。
編寫一個靜態province.html頁面,其中使用一個二維數組來裝載所有數據,然后分析和編碼實現省份與城市的聯動下拉列表框。
編寫一個靜態jsonProvince.html頁面,其中使用JSON對象方式來裝載所有數據,然后分析和編碼實現此種數據格式下的省份與城市的聯動下拉列表框。
對於靜態網頁顯示省份和城市,首先要考慮用什么樣的數據結構來存儲所有信息,每個選項信息包括名稱和id,如果單獨用一個數組保存各個省份,再用一個數組保存各個省份下的城市,是可以的,但是需要在兩個地方維護數據,要保持數據的同步。提示:由於學員基礎的緣故,對於此部分的講解,一定要寫一些示意代碼來進行說明。
與其如此,還不如用一個數組把省份和省份下的城市全部保存起來。
沒有唯一和最好的數據存儲結構,只有最適合你和你認為不錯的數據存儲結構,首先考慮的是把功能實現出來,其次才是考慮哪種方式更優雅和方便些。在講課時,對於二維數組和json數據結構,都是先把寫好的靜態province.html頁面中的各個函數刪除掉,然后讓同學們自己去完成這些函數,這樣同學們的學習興致很高,確實也能讓同學們馬上就感到有收獲和有進步。
在編寫觸發的顯示某個省份下面的城市的js函數時,先簡單地alert一下選中的省份的值。
//下面代碼在firefox下不成功!
//document.getElementById("provinceId").add(optProvince);
//document.getElementById("provinceId").options.remove(i);
//下面代碼在firefox下成功!
document.getElementById("provinceId").options.add(optProvince);
document.getElementById("provinceId").remove(i);
聯動下拉:動態生成數據的方式
實驗步驟:
編寫一個ListProvinceAction的Action和相應的province.jsp頁面,留出數據待填充,大家清晰看到后面的任務就是生成出數據。
創建代表省份與城市的province和City實體類,然后將相應的實體對象存放在一個單例的MemoryDao中,用一個ArrayList集合存儲所有Province對象,Province對象中保存有一個City對象的集合,在MemoryDao中構建出各個對象及關系。
創建ProvinceService類獲取所有省份列表和CityService類獲取某個省份下的所有城市。
在ListProvinceAction中編寫拼湊出JSP頁面所需要的那個數組字符串。
編寫一個ListJsonProvinceAction的Action和相應的jsonProvince.jsp頁面,以生成使用JSON對象來裝載所有數據,為了方便拼湊JSON格式的字符串,在各個實體對象中覆蓋toString方法返回自身的JSON格式字符串,這要比在外面最后統一轉換成一個JSON字符串的做法要優雅很多,這種分而治之的思想使得程序健壯且易於維護。
編寫一個ListJsonProvince2Action的Action,快速演示和說明一下如何在其內部用JSONObject與JSONArray工具里來完成json字符串的生成工作。
使用StringBuilder拼湊字符串時,講解了其與StringBuffer的區別,線程安全好比人走路,如果總是考慮怕與別人或汽車相撞,那走路速度慢,如果不花精力去注意別人,只管埋頭走路,速度肯定要快。如果知道是單行通道走,那么就可以不去考慮別人,只管自己一個人埋頭走路好了。
當要將ArrayList中的元素轉換成js的json格式的字符串輸出時,不需要自己再去拼湊字符串,可以直接調用ArrayList的toString方法,該方法輸出的字符串正好就符合json數組的語法規范。
聯動下拉:用Ajax方式實現的思路分析
傳統方式與Ajax實現方式的對比與選擇:
好比飯館上菜的方式:一種是先讓用戶等較長時間,最后一下子將所有的菜全部上上來,一般的火鍋店都是這么做的,還有一種方式就是做好一盤菜就上一盤菜,用戶等待的時間較短,但送餐服務員要跑好多次,一般的家常菜飯店都是這么做的。
如何選擇:傳統方式是一下子把所有數據搞到手,以后只是用js把到手的數據顯示出來即可,第一次得到數據的時間比較長,如果這個時間長得影響了用戶的感受,那就考慮用ajax進行改進,否則,可以直接使用傳統方式。
如果將傳統方式改造為ajax方式的總結:將原有的一個jsp頁面改為兩個jsp頁面來實現,第一個頁面為那些固定不變的內容和javascript代碼,第二個頁面為那些要改變的區域的代碼,因此原來用一個action或servlet實現的代碼要改變為用兩個action或servlet來實現,這稱為二步視圖法。
實現的思路剖析:
第一次要獲得一個頁面,瀏覽器以后一直顯示這個頁面,以后的每個操作都觸發這個頁面內部的一個javascript函數,再由這個javascript函數去發請求和處理回應結果。
第一次獲得的頁面應該包含什么信息?頁面的初始內容和javascript函數。
以后的每次請求要獲得什么樣的結果?
如果本應用只顯示幾個省份及各個省份下面的少數幾個城市,則可以用傳統方式。如果本應用是要顯示出全國所有省份下面的所有城市,涉及的數據量就比較大了,如果要從數據庫中一下子查出31個省和它們下面的所有城市,通常要涉及32條sql語句,花費的時間較長;如果改為Ajax按需取數據的方式,即選擇哪個省份后,再去取該省份下的城市,這樣,第一次展現的速度就較快。給大家看看騰訊的網吧充值界面圖。
聯動下拉:用json數據傳輸格式的Ajax方式實現
步驟:
編寫AjaxListProvince的Action和ajaxProvince.jsp頁面,在一個下拉列表框中列出所有省份,編寫觸發和發送獲取某個省份下面的城市的請求消息的代碼,先簡單的alert一下響應結果。
根據客戶端的請求信息,分析和編寫一個ListCities的Action調用CityService類獲取某個省份下的所有城市,Action返回一個包含有某個省份下的所有City的json格式的數組。
在ajaxProvince.jsp頁面中編寫處理返回結果的javascript代碼,使用javascript自己的eval方法處理json字符串。
改進為用prototype自己的json支持來處理返回的json串,包括擴展的String.evalJSON()方法和transport.responseJSON屬性這兩種方式。
由於本例子程序返回的城市對象很簡單,可以使用一個map來表示某個省份下的所有City信息,同時簡化客戶端的javascript代碼。
編寫jsp頁面,因為沒有涉及<html:form>表單,所以無法使用struts的html:optionCollections標簽來生成下拉列表框的option選項,只能使用jstl標簽。
注意:改為ajax方式來實現時,傳遞給事件處理函數中的參數不再是選擇項的索引號,而是選擇項的值了,因為每次都要從服務器端來獲取某個省份下的城市集合,傳給服務器的參數是省份的id值。
瀏覽器一上來要發兩次請求,第一次得到省份,第二次得到當前選中的省份的城市信息,而不是一次就得到省份和第一個省份的城市信息,一個模塊專門負責省份,不要讓它既處理省份,又處理城市。
學員在做第二步時,做好ListCityAction后,先用瀏覽器測試一下,然后用ajax調用,在ajax調用的回調函數中,先alert一下返回的這個串,最后再把這個串轉換成為json對象。
在baidu中搜素”jquery select 添加選項”
學員寫的一段代碼:
for(var i=0;i<data.length;i++){
var op=$("<option>").attr('id',data[i][1]).html(data[i][0]);
$("#provinceId").append(op);
}
分別用jquery和protoye做一遍。Jquery的json支持做一遍。Onchange事件用prototype和jquery提供的方式來注冊。對於清楚下拉列表框中的所有選項,可以使用jquery對象的empty函數或者讓其innerHTML為空。用jquery時,最好是把事件處理的注冊代碼放在js中寫,而不是放在html中,所謂的內容與行為相分離,術語借鑒了內容與表現相分離的說法。
有學員提到了如何自己實現緩存,借此機會正好把緩存給實現了一下:
可以用數組方式實現,用其id值作為數組元素的索引,如果id=99,測試數組的長度一下就變成了100,所有這樣不合理,代碼如下:
var data=[];
data[pid] = cities;
alert(data.length);
於是想到改為用對象方式來實現:
var data={};
data[pid] = cities;
for(var a in data)
{
alert(a + “:” + data[a]);
}
后來用數組進行循環,發現實際上也只有添加進去的幾個元素,這里數組與對象的區別似乎就是對象沒有length屬性。
有問題:$("#provinceId").change(fillCity($(this).val()));
正確: $("#provinceId").change(function(){
fillCity($(this).val());
});
用jquery.each方法迭代出來元素是htmlelement類型,而不是jquery對象。可以使用nodeName來查看htmlelement元素名。
聯動下拉:用xml數據傳輸格式的Ajax方式實現
步驟:
編寫一個ListCity2的Action,返回一個包含有某個省份下的所有City的xml文檔。
直接用瀏覽器訪問ListCity2,測試查看返回的xml文檔內容是否正確。
客戶端頁面改為ajaxProvince2.jsp,在其中編寫解析xml文檔內容和將結果顯示在下拉列表框中的代碼,並且將AjaxListProvince配置為/ AjaxListProvince2.do
今天用jquery做時,只要在發送請求時,將dataType:’xml’,那么,jquery就回將xml文檔轉換成Document對象,並將該Document對象作為參數傳遞給回調函數,也就是說,此時的回調函數接收的參數就是Document對象。
/*拼出如下的數據格式,該如何做呢?
*
<cities>
<city>
<id></id>
<name></name>
</city>
<city>
<id></id>
<name></name>
</city>
</cities>
*/
Jsp就是拼湊大段字符串的技術,是模板技術,大量固定不變的串中偶爾要夾雜一點變化的數據,這就是jsp的用武之地。
jsp就是為了方便拼湊大量文本串而推出的技術,我們為何放着這么好的東西不用呢?
不需要寫AjaxListProvince2Action,只需要把AjaxListProvinceAction再配置一遍,這正是mvc的優點,控制器和模型不變,可輕松改變視圖(view)
聯動下拉:返回整個下拉列表框的HTML代碼
步驟:
編寫一個ListCity3的Action,返回一個包含有某個省份下的所有City的下拉列表框的html代碼。
直接用瀏覽器訪問ListCity3,測試查看返回的html代碼是否正確。
客戶端頁面改為AjaxProvince3.jsp 和在其中定義一個<div>元素來容納服務器返回的下拉列表框,並且將AjaxListProvince配置為/ AjaxListProvince3.do。
為什么有了前面兩種非常優雅的做法,還要講那些不優雅和很土的做法呢?因為外面有些公司用的就是土方法,真正用優雅方式的是很牛的好公司,這樣的好公司並不多,外面的公司為什么要用土方法呢?好比你讀了小學一年級就可以掙錢了,以后一直忙於掙錢,就沒必要去讀博士了,所以一直會用小學一年級的方式工作下去。雖然你讀博士后,掌握了只有博士能掙到的錢的本領,掙錢的方式可能更優雅,但有時候,博士也要用小學一年級的方式去掙錢,例如,有的博士是房產公司的經理,但他掙錢的方式很原始,完全是小學一年級水平的方式,只要會送禮和會喝酒就可以,讀博士掌握的本領全用不上也是可能的。
大家對有的Action用response.getWriter()方法直接輸出結果,對有的Action卻跳轉到一個jsp頁面上的關系與區別總是搞不太清楚,問這問題的人都是屬於基礎比較不錯,已經開動了腦筋的學員。看來大家對jsp的根本作用和工作原理了解得還是不夠好。
返回的html代碼片段前面有幾個空格和換行,導致顯示的城市下拉列表框與省份下來列表框之間有很大的空襲,我是讓返回的html代碼前時盡量去掉前面的空格,這時候應該用prototype或jquery提供的去掉兩端空格的方法來完成。
聯動下拉:返回向下拉列表框填充選項的js代碼
步驟:
編寫一個ListCity4的Action,返回一個用於將某個省份下的所有City添加進下拉列表框的javascript代碼。
直接用瀏覽器訪問ListCity4,測試查看返回的javascript代碼是否正確。
客戶端頁面改為AjaxProvince4.jsp 和使用eval方法執行服務器端返回的javascript代碼,並且將AjaxListProvince配置為/ AjaxListProvince4.do。
這種方式既不優雅,也不簡單,但有人用,我覺得完全是無用,毫無價值。
今天用jquery做時,首先用eval(“(“ + msg + “)”)執行時,ie總是報告錯誤,說缺少),換成firefox查看,提示錯誤如下:
missing ) in parenthetical
document.getElementById('cityId').options.add(new Option('武漢',3));\n
原來是在返回的字符串最后多了個\n,把整個串用()括起來后,就相當於一個完整的字符串中間換行鍘成兩段,這種語法是不行的。
於是,去掉(),即代碼改為eval(msg),再運行,結果就正常了。
最后讀jquery的Ajax函數的文檔,發現dataType選項有一個設置值為script,於是設置了這個選項,發現city的填充效果被double,
這說明將dataType設置為script后,jquery會自動幫我們執行javascript代碼,在這種情況下,不寫success回調函數也可以看到運行效果。
-------------------------------------------------------------------------------------------
最后要給大家總結一下,這樣大家思路就不混亂了:對於用4種不同方式返回城市,第一步顯示省份的頁面需要做幾個?返回省份信息的前置Action需要寫幾個。
對於第二步返回城市信息,除了json之外的3種方式需要做幾個頁面?需要做幾個返回城市信息的Action?為什么返回json數據時的Action與返回其他數據時的Action不同?
案例擴展:多級地區的動態展現
實驗步驟:
演示和分析程序運行的效果。(每選擇一個區域,則顯示一個包含有其所有子區域的下拉列表框,並清除其他不相關的下拉列表框;當選擇了某個沒有子區域的選項后,不再顯示出新的下拉列表框,而是顯示該區域的網吧)
分析數據庫表結構該如何設計,並執行預備的腳本文件創建表結構和數據。
分析JSP頁面該如何設計:
第一個返回的頁面應該包含哪些內容?
以后每次請求獲得的結果是什么?返回的結果怎樣展現在返回的第一個頁面中?動態生成出下拉列表框和將下拉列表框追加到其他列表框后面,或者提前預定義若干span元素,將新增的下拉列表框添加到相應的span元素中。如果要實現用表格來顯示某個區域的網吧,服務器端返回的要么是select元素,要么是table元素,客戶端要判斷結果的類型。
編碼實現:先用span的方式實現;再用prototype的刪除和添加功能。
我是一個通用的產品,要賣給不同的公司,不同公司的級別分類的層次是不一樣,我們通常應該允許無限極分類,還有書的分類,這樣的系統的數據庫該如何設計。是設計無限個表,還是設計一個表。無限級分類應用很多,例如論壇的版面,帖子的回復等等。
id,name,parentid
1, 集團,0
2. 一公司, 1
3. 二公司, 1
4.三公司,1,3
查詢集團下的直接子部門:select * from dept where parentid=0;
查詢一公司下的直接子部門:select * from dept where parentid=1;
為一公司添加子部門:insert into detp values(..,1)
父親可以知道自己的所有孩子,孩子可以知道自己的父親,這就很滿足需求了嘛!
網吧為什么要有一個字段指向所屬的區別?因為要列出一個區域下的所有網吧,如果沒這需求,當然也就不需要那個字段了。
這里的第一步不需要顯示出所有省份,因為顯示省份的方式和顯示子地區的方式完全一樣,所以,顯示省份信息借助第二部操作來完成,只是第一步做完后立即進入第二步弄出省份。
先不做網吧部分,等做完地區后,讓學員看看使用dao查詢網吧只是復制工作,環境搭建只是一次性的工作,只要環境搭建好了,開發過程就是這樣的拷貝和復制。
對於采用span元素的實現方式,每個下拉列表框都要用同一個函數來實現,這個函數需要接受兩個參數:要顯示的地區的父級id(即列表框要顯示哪個id地區下的子地區),得到顯示的結果放在哪個span元素里。先完全用手工編寫方式分析服務器每次返回的下拉列表框的html代碼怎樣?再分析用jsp如何生成,由於返回的結果既要有某個id的子地區,又要在生成的下拉列表框的onchange事件中指定下一級地區列表框所放置的span元素,所以,傳遞給服務器的參數也要有兩個。如果不給服務器傳遞當前span元素的id值,而是等服務器返回一個結果后,然后客戶端再用js代碼來指定下一個span元素的id值,這樣更好,因為服務器端不用考慮客戶端的頁面情況了,即服務器端的代碼不用隨客戶端頁面的改動(地區級別)而改變,這中方式可以留給同學們自己做。對於這種情況,js代碼中還要判斷服務器返回的是<select>還是<table>,是table則往網吧的<span>中填寫。
每次添加新的下拉列表框前,都是刪除原來的當前要生成的下拉列表框以后的所有列表框和表格,再更新當前要生成的下拉列表框。這里操作的參數是指當前要生成的下拉列表框所在的span元素的id。
對於采用prototype的添加和刪除功能,得到所有弟弟並刪除,增加新弟弟。有一點奇怪的是,使用$(sibling).remove方法,無法完成刪除功能,但使用Element.remove(sibling)卻可以,其中具體的差別在哪,還沒有找出來。另外每次生成一個下拉列表框,然后再刪除,再添加,下次生成的下拉列表框與上次生成的下拉列表框有一定的距離,這就是因為返回的<select>標簽前面有空格導致的。也可以利用Prototype提供了Element.cleanWhiteSpace方法來清除所有空格。
每次添加新的下拉列表框前,如果不是第一個(通過調用函數時,有無傳遞當前元素這個參數來判斷),則刪除當前發生事件的下拉列表框以后的弟弟(包括所有后續列表框和表格),再新增一個下拉列表框,如果是第一個,則直接新加。這里的參數是當前正在發生事件的下拉列表框。
設計多級分類,可以使用字符串類型的id,用id的值來表示級別和隸屬關系,例如,001,001001,001002,001001001等。這是我們十年前總是樂意當着一個經驗向大家講解的知識,現在由於掌握的新技術太多了,都忘記講這些以前的經驗了,可能是人都有點喜新厭舊的習慣吧。其實,對於新手來說,我們這些老多年前的經驗仍然是很有價值的。
一道面試題:把span1變成span2,把span2變成span3,把span3變成span4,把span5變成span6
