做一個WEB程序,能夠在盡量修改極少程序代碼的情況下,輕松制定皮膚以及切換皮膚,應該都是需要的,誰也不想,在網站界面想要改版的時候,要改一大片邏輯代碼。
一個合格的皮膚機制體系的實現,應該要做到以下幾點:
->頁面模板上要極少擁有邏輯代碼(如果模板上擁有大量邏輯代碼,那估計這個也不叫作模板了)。
->能夠輕松改變頁面布局,同時不影響程序代碼(.cs)。
->新模板的定制,基本上能由皮膚制作者參照舊模板自行完成,不需要開發人員太多介入。
->保持性能。
然後,來看看,都有哪些方法大家用來實現所謂的皮膚機制,同時進行各個方法的一些個人說明。
1. 改變頁面調用的CSS文件來換膚。
這一個,嚴格上來講,不應該算作皮膚機制。雖然CSS非常強大,也能夠通過它來任意改變頁面元素布局,但它的Html始終是不變的,所以局限性是非常大的。
優點:完全不影響性能,甚至可以完全不由服務端代碼來管理它的變換,可以使用JS來切換皮膚(由此,在我們有一套完美皮膚機制的情況下,這種方法,可以完全不與此機制沖突,讓用戶在客戶端作更多的個性化)。
缺點:如果作為核心皮膚機制的話,非常有局限性。
示例:如QQ.COM, 114LA.COM上面的一些可點擊的小色塊,就是改變調用的CSS文件來實現換膚。
2. 讀取模板文件,替換標識符為要顯示的內容與數據輸出。
這一個方法的靈活性比較高,每套皮膚可以有自己的布局,有自己的個性。
實現:比如模板中有一個標識$Subject,程序代碼會把它替換成文章標題,然後有一個標識塊<!—Loop[ArticleList]--><h1>$Subject</h1><div>$Content</div><!--/Loop-->,程序代碼會把它替換成一個文章列表,最後輸出處理完所有標識符的內容。
通常,我們會緩存讀取到的模板內容,但字符串的替換始終不可避免,或者也會把替換過的內容也緩存起來,但這樣子,就等於要緩存模板內容以及替換過的內容,占用了兩份似乎挺重復內容的內存(為什麼?不然總不該每次數據有改變的時候就去作IO操作讀取操作讀模板文件吧,這似乎比字符串替換性能更差)。
優點:模板靈活程度很高,可以隨便改動頁面布局。
缺點:影響性能,開發人員維護難,必須有特定的標識符來表示頁面變量,後期維護可能會帶來非常多的問題。
3.使用ASP.Net的App_Themes。
這一個方法,應該是極差的一個方法,根本只是ASP.Net的一個小纂頭,雞肋,基本上不實用。
實現:比如,定制一個BUTTON的樣式是這樣子的,<ASP:buttonrunat="server" BackColor="lightblue"ForeColor="black" />,類似這樣的代碼,存在於.skin文件中。然後它的換膚機制如下,<%@ Page Language="C#" Theme="default" %>。在App_Themes目錄下,是各套皮膚的獨立文件夾,各個文件夾包含皮膚的樣式以及圖片文件等等,也可以包含.skin文件。
優點:只有ASP.Net才有
缺點:包含了第一種方法的缺點,.skin的樣式定制方式還要嚴重依賴使用ASP.Net服務端控件,同時也影響性能,靈活性也極低。
4.動態載入.ASCX文件(ASP.Net用戶控件)|| 使用.master(母版)。
這個方法,應該也是很多使用ASP.Net的人使用的方法,有時候,它還會與第三種方法結合使用。如果對性能需求不是很嚴格的話,中小型項目可以使用。
實現:使用LoadControl()動態載入.ASCX文件或(與)指定頁面的MasterPageFile(目標皮膚文件夾的)實現(通常.ascx與.master還會結合使用)。
優點:靈活性極高,每個皮膚有獨立的布局,直接使用了.CS文件的變量與方法ETC…甚至每套皮膚還有自己獨立的代碼文件。
缺點:影響性能。有興趣可以自己去反編譯LoadControl方法。同時,在頁面要使用<%%>這種代碼塊,有時候感覺也有點不雅。
5.XML + xslt
傳說XML取代Html是趨勢??不清楚,不了解。應該不可能。此種方法我沒有深入了解過,不過大概實現應該是要這樣子?每一個XML(輸出數據)會有一個對應的XSL文件(控制樣式)。如下:
XML文件:
<?XML version="1.0"encoding="ISO-8859-1" ?>
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>two of our famous Belgian Waffles with plenty of real maplesyrup</description>
<calorIEs>650</calorIEs>
</food>
<food>
<name>Cakes</name>
<price>$1.95</price>
<description>sweet cakes</description>
<calorIEs>2650</calorIEs>
</food>
</breakfast_menu>
xsl文件:
<?XMLversion="1.0" encoding="ISO-8859-1" ?>
<Html xsl:version="1.0"XMLns:xsl="http://www.w3.org/1999/XSL/Transform"XMLns="http://www.w3.org/1999/xHtml">
<body >
<xsl:for-each select="breakfast_menu/food">
<div >
<span >
<xsl:value-of select="name" />
</span>
<xsl:value-of select="price" />
</div>
<div>
<xsl:value-of select="description" />
<span >
<xsl:value-of select="calorIEs" />
</span>
</div>
</xsl:for-each>
</body>
</Html>
這樣子做,有什麼好處麼,我沒有體驗到。
6.讀取模板文件,生成.ASPx文件到每套皮膚的獨立文件夾下,通過地址重寫指定到這些文件夾。
這個方法的最終效果對於用戶來說,和第二種方法應該是差不多的,優點就是性能比較高,而且還能直接使用.CS代碼裡面的變量方法ETC…另外,也可以不會有<%%>代碼塊的存在,可以存在自己的模板語言,如同第二種方法的$Subject, <!—Loop-->標識符一般。
優點:幾乎不影響性能,只有第一次讀取生成.ASPX文件需要損失性能。靈活性極高。模板代碼可讀性也可以實現到很高。
缺點:啟動時需要讀取分析時間(不過,這應該算是小問題),另外,有一套皮膚,它就要生成與之對應的一套.ASPX文件(當然這個可以解決)。
7.利用ASP.Net2.0開始才擁有的VirtualPathProvider來實現。
虛擬文件機制。這個,應該算是第六種方法的加強版。最終的效果,和第六種差不多,只是不會生成那些.ASPX文件而已,取而代之的,便是長駐在內存中。
實現:實現兩個類,一個繼承至VirtualPathProvider,一個繼承至SkinFile。VirtualPathProvider裡有個FileExists方法,重寫成判斷請求的路徑是否是皮膚文件路徑,如果是,GetFile就實例一個SkinFile(這一個SkinFile,我們會對模板進行處理,可以擁有自己的模板語言)。另外有一個GetCacheDependency方法,可以來將模板文件作為虛擬文件機制的緩存依賴文件,一旦模板文件被修改了,它就會再重新解析模板文件。這裡先不作贅述,具體的,查看MSDN的相關文檔,具可了解。
優點:與6相同。
缺點:第一次啟動需要損失性能(但這也不可避免)。
8.還有更多的實現方法,還沒用過,個人先不發表觀點,比如:使用BuildProvider,但這一個,需要有比較強的詞法分析與語法分析能力。