1. 程式人生 > >網頁中的伺服器端和客戶端指令碼

網頁中的伺服器端和客戶端指令碼

引言:
    最近看北大青鳥視訊的時候有一集裡面提到了關於網頁中伺服器端和客戶端指令碼的區別,所以特地查了查,覺得這個部落格寫的蠻好的,於是重新整理了一遍。

  步入.Net時代,MS想讓人們把網頁開發當成應用程式一樣開發,而且還在ASP.Net 2.0加了很多控制元件,像Loginform,Treeview等等。但在網頁尾本語言(如ASP、PHP、Perl等)和J2EE還在繼續佔領著WWW大部分江山的情況下,如果只懂得寫codebehide裡的東東是遠遠不夠的。 


  現在很多ASP.Net初學者居然都不知道何為JavaScript,或者只是聽說過,而不甚瞭解。比如很多新手問這樣的問題:

如何用ASP/ASP.Net彈出一個對話方塊?

    儘管這對一個網頁老手來說是輕而易舉、嗤之以鼻的小事,甚至他們會大惑不解,連這都不懂還來編網頁?

這正是應用程式和網頁的最大區別,網頁是由HTML、CSS、客戶端指令碼、行為等等各種元素組成的複雜產物,因為不能與Web伺服器保持實時連線,所以很多東西不能由伺服器端來控制。

    我期待著MS將如何填補這道溝壑,希望在VS.Net2005正式版中能看到一些改變(一直在想MS是否有可能把彈出對話方塊做成一個控制元件或包裝成Web.MessageBox類,呵呵)。VS.Net 2003中根本沒看到對方便編寫客戶端指令碼的支援,這又是出於怎樣的考慮? 


  還有一個問題也是值得斟酌的:ASP.Net的提出應該是針對企業級使用者的多層架構需求,而現在盲目地把它用於開發普通的網站,VS.Net預設產生的大量垃圾網頁程式碼對於現在平均頻寬以K計的中國(CNNIC2005年最新的統計報告表明撥號和ISDN佔44.5%的使用者數量,)是否過於累贅呢?

    不再強調使用CSS檔案;不再強調使用SSI(Server Side Include);自動產生的一堆加密JS控制指令碼;一旦編寫不當動輒提交整個網頁來獲取少量的資料:這些無論對伺服器還是客戶都加重了負擔……看來ASP.Net更需要知識全面縝密的程式設計師! 

  一般介紹動態網頁開發的資料都會機械式地先講HTML,再則有空講講JS,然後切入正題講動態網頁部分,最後給出一些例項,比如留言板、論壇,甚至小型電子商務網站等等。

    而更新的ASP.Net甚至可能只從WinForm講起,然後就講WebForm了……這樣更加使程式設計師無法接觸底層的程式碼,無法理解整體架構和工作流程。

    我認為ASP.Net的出現有點像高階語言的誕生,高階語言的編譯器實現了自動編譯連結高階語言程式碼到彙編程式碼的過程,雖然最終的程式碼未必那麼簡潔,但畢竟經多重優化也在可接受範圍內。而如今的ASP.Net原意想封裝所有的客戶端程式碼,實現從WebUI+CodeBehide到HTML的自動生成過程,但由於種種原因現在還做不到完全滿足開發者需要(可以這麼說,它產生的“彙編程式碼”不盡如人意),很多基本功能需要了解客戶端指令碼,進行手工修改才能實現。 

    正是ASP.Net現在所處的這種矛盾階段,我們更有理由要掌握更多的知識,從HTML、CSS到JScript、behavior、XML。

    言歸正傳,本文將直接把伺服器端指令碼和客戶端指令碼放在一塊講述比較,這是極少有人做過的,也可以解開一些入門者的困惑:

    比如為什麼伺服器端指令碼就是不能彈出一個對話方塊、彈出確定框、開啟新視窗等等問題。

    再看看這二者到底管轄和作用了怎樣的範圍,然後再舉例來認識一下如何使這兩個指令碼間可以互動,以實現更強的功能。 

  

    圖為早期PHP4的分層示意,雖然從現在的n層架構來看畫得不甚清楚,但還是能看懂的。

    兩個指令碼很簡單:顧名思義,一個執行在伺服器端,一個執行在客戶端。

    而它們的任務也很明確:伺服器端指令碼只用於生成網頁程式碼(可以包括HTML、CSS、JS等等),它正是平常所說的ASP/ASP.Net、PHP、JSP等等,在動態網頁中一般用“<%%>”、“<??>”等符號包圍,在多層構架中也可以把Beans,CodeBehide等等算進去吧。

    客戶端指令碼就完全是在客戶瀏覽器裡解釋執行的,要麼在“<script>”中,要麼在一些事件裡,要麼單獨一個檔案,總之檢視原始碼一般都可以看到,對最終瀏覽使用者相對是公開的。它控制著使用者與瀏覽器的互動,如果把瀏覽器看成應用程式,它的所有動作都是客戶端指令碼完成的,這就解釋了為什麼總是沒有彈出對話方塊的伺服器端函式。 

  【問題】因為ASP本身用的指令碼與客戶端指令碼完全一樣,都是JScript(或JavaScript)和VBScript,所以經常讓初學者感到摸不著頭腦,還有很容易使人混淆的<script runat="Server">這個標誌。

    【解答】其實還是上面說的原則,用“<%%>”包圍起來的程式碼肯定是伺服器端指令碼,當然還有<script runat="Server">裡的(這不都標明瞭是執行在伺服器端的嘛),這些程式碼經過Web伺服器解釋執行後在最後的HTML程式碼中肯定是找不到的。還有一點要明白的是,無論是JS還是VBS都可以用來寫任何一端的指令碼,只是一般比較習慣用JS來寫客戶端指令碼罷了。至於一般用VBS來寫伺服器端指令碼可能一個是習慣,一個是以示區別。 


  ASP.Net用RegisterClientScriptBlock()、RegisterStartupScript()等方法來在程式碼中新增客戶端指令碼,以及control.Attributes["event"]="script"來為控制元件新增事件處理指令碼。

    懂得這些和一點JScript知識你也許知道如何實現在按個刪除按鈕之前彈出一個確認視窗了,把下面程式碼寫在Page_Load裡:

<span style="font-family:KaiTi_GB2312;"><span style="font-family:FangSong_GB2312;font-size:18px;">btnDel.Attributes["onClick"]="return confirm('確定要刪除嗎?');";</span></span>

  但如果你多懂得一點內幕,馬上就會發現這樣雖然能行,但是有很致命的副作用:如果同一頁面中設有validator,儘管validator可以報告有錯誤的輸入,但它們都不能阻止表單提交了!原因在於ASP.Net把你自己寫的那段JScript程式碼寫在了按鈕onclick的最前面:

<span style="font-family:KaiTi_GB2312;"><span style="font-family:FangSong_GB2312;font-size:18px;"><input type="submit" name="btnDel" value="Button" onclick="return confirm('確定要刪除嗎?');if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="btnDel" style="……" /></span></span>

 這樣原來的if語句後的那條就無法執行了,而Page_ClientValidate()正是ASP.Net自帶WebUIValidation.js裡的函式,而一旦影響該函式的正常執行則會使表單不能按原定的方式判斷提交。奇怪的是MS自身提供的範例也有這麼做的。我們稍微更改一下onClick的指令碼來獲得正確的做法:

<span style="font-family:KaiTi_GB2312;">btnDel.Attributes["onClick"]="if(!confirm('確定要刪除嗎?')) return false;";</span>

    可見客戶端指令碼的使用是無處不在的,有時需要熟練的技巧和敏銳的決策,在過去的ASP時代如此,現在的.Net時代亦不外如是。 

  懂客戶端指令碼的未必是好的Web程式設計師,但只懂伺服器端指令碼或程式設計的肯定不會是好的Web程式設計師。至少在現今階段,要寫出高效Web網頁或Web應用程式,不對這兩個指令碼充分理解熟諳於心是不行的。聰明的程式設計師能靈活使用指令碼,對各種Web程式的業務流程得心應手。 
  比較常用的技巧是用伺服器端指令碼來寫客戶端指令碼,這裡用一個較流行的區域性重新整理的例子來展示該技巧。前提是對客戶端指令碼有較好的瞭解。 
  “<script>”標籤有個屬性src,其值可以設定為一個js檔案,檔案中即是客戶端指令碼。因為沒規定該js檔案是靜態檔案,而且可以用指令碼來更改src指向的檔案,所以可以巧妙地使用這個特性來實現動態區域性重新整理(當然,frame、iframe等也有src屬性,均可考慮,這裡用script方便一點)。這裡有兩個網頁,一個test1.htm是主頁面,而另一個test.asp其實是js檔案,只不過它的內容是動態的。 
test1.htm

<input name="txt" type="text" size="10" maxlength="10" /> 
<script id="s" src="test.asp"></script> 
</script> 
function func(){ 
  s.src="test.asp"; 
  txt.value=sTxt; 
} 
setInterval("func()",1000); 
</script> 


test.asp

//JScript 
<% 
response.cachecontrol="no-cache" ' 不使用快取,確保頁面更新 
sTxt=… ' 動態地獲得一個值 
%> 
sTxt="<%=sTxt%>"; //注意這裡兩個sTxt,前一個是客戶端,後一個是伺服器端變數 

  這樣在主頁面test1.htm中每隔1秒就會看到文字框“重新整理”一次,實現了局部重新整理。把該技術加以擴充套件推廣可以滿足更復雜的需求。注意理解test.asp中的兩個sTxt變數及兩種註釋方法,記住ASP是寫在<%%>中的,是用VBScript寫的,所以註釋用單引號“'”;客戶端指令碼用JScript寫的,所以註釋用兩個斜槓“//”。

 
  這是伺服器端指令碼把變數傳給客戶端指令碼的例子,如果還不明白就動手做做實驗,在瀏覽器中輸入test.asp地址看它到底輸出了什麼。至於客戶端指令碼把變數傳給伺服器端的例子就司空見慣,平常用得再多也不過了,如表單資料提交之前的簡單處理再交給伺服器就是一例,這裡就不具體闡述了。所以也許在不知不覺中我們就在做著二個指令碼之間的互動工作。 


  最近又看到有人用JS在客戶端建立XMLHTTP元件來讀網頁來實現區域性重新整理,當然這種技術是無法跨平臺的;還有Web Service、Remoting等技術來實現區域性重新整理,都是不錯的主意,自從MS的JScript可以建立ActiveX物件,逐漸支援面向物件特性後,客戶端指令碼威力愈發強大。對我們來說,一旦分清楚伺服器端和客戶端指令碼的轄區及作用,下功夫看些網頁客戶端指令碼語言知識,善用指令碼互動,就不難理清Web程式的思路,開啟層層迷障,完成各種任務!