對於BS管理系統,我很長一段時間都工作在Asp.Net Web Form上,Web Form的主要優勢是可以使用服務器端控件,以類似CS的開發模式進行工作,通過拖拽控件和定義事件處理函數,極大的簡化了BS的開發。服務器端控件會在渲染階段把自身輸出為Html標簽,對我們完全透明,當需要設置相關屬性時,只需要在屬性面板上操作即可。
Web Form在誕生之時,Ajax還未流行,所以頁面的提交是完全刷新方式。為了記住控件的狀態,Web Form引入了ViewState和回發機制。對於一些復雜的界面,可能創建大量的服務端控件,查看ViewState序列化生成的hidden,有時候達到數百K。回發機制也讓人郁悶,手工編寫的Js與回發機制不能很好的配合,經常發現代碼的執行時機不對。Web Form服務端控件生成的Html也相當雜亂,基本是面向機器的。
當然這些問題很多時候是自己的使用方式不對,不能全賴到Web Form上,但大家希望.Net能夠提供更好的解決方案。
Ajax逐漸流行,對BS的要求大幅提升,比如局部刷新,干凈整潔的Html等。一些 RIA框架發展起來,比如Ext、EasyUi、Dwz等。
微軟也推出了輕量級的Mvc框架,我是在Mvc 3 發布時才開始使用的,主要是被Razor視圖引擎吸引過來。為了提升用戶體驗,還選擇了一款RIA框架,當時選擇了Dwz,主要是它開源免費,而其它框架要么閉源,要么收費,或者太復雜了,學習成本高。
在使用了幾年Dwz之后,最近決定更換一個前端框架,下面談談使用Dwz的一些情況。
Dwz作為一款國產免費的開源框架是值得支持的,官網http://www.j-ui.com。通過Dwz,我學習到大量Js和Css的相關知識,在此表示感謝。
Dwz基於JQuery,設計以Html擴展為主,對SPA (single page applications, 單頁應用程序)有很好的支持,API命名規范,代碼質量較高。
使用中碰到的問題也不少,首先是缺乏專業的文檔,官方只提供了一個很簡單的使用手冊,每當碰到問題,我總是進入dwz源碼斷點調試,不過這樣更能深入學習內部機制,似乎也不算嚴重的缺點。
從我開始使用Dwz,好像就沒見更新過。
Dwz有些組件不夠完善,比如彈出模態窗口,只支持彈出一層,如果在彈出的模態窗口上繼續彈出模態窗就不支持了,而這屬於常用功能,對於這些小功能,我自己修改,咬咬牙也還是可以搞出來。
對於一些重量級的組件,比如表格、樹等,Dwz提供的比較弱,我一般都引入第三方插件,比如ZTree。
還有一個頭痛的問題是布局,Dwz沒有提供border或fit這樣易用的布局方式,除了面板和Tabs等常規布局組件外,只有一個神秘的layoutH屬性,它的值是一個數字,表示工具欄的高度,對於一個復雜點的布局,我經常東調西試以找出這個正確的數字。當然這也只能怪我水平有限,掌握不夠好,所以引入一個更強大的前端框架就迫在眉睫。
對於大名鼎鼎的Ext,我已經關注它很長時間,不過一直沒敢使用它,有幾個原因。使用純Js開發界面,有點違反一般程序員的習慣,大部分程序員還是喜歡用Html布局。另一個原因是面向對象的Js要求比較高,API豐富而龐大,學習成本高。當然最重要的一個原因是,對於管理后台這樣的系統,大量手寫Js開發效率低,且Js是弱類型語言,代碼提示很弱,且沒有編譯時檢查,容易出錯,健壯性差。所以哪怕要使用Ext,我也會用C#來包裝一次,這個工作已經有人做了,這就是Ext.Net。十分遺憾的是,Ext.Net不是開源的,而且還收費,它甚至把js等資源內嵌到dll中,另外還不支持DataAnnotations驗證,這讓我打消了使用它的念頭。
Ext也是要收費的,但有一個版本2.0.2可以免費使用,我的想法是,如果做小項目,就用高版本,偷偷的用估計也沒人知道,如果需要公開使用,就切換到2.0.2這個版本。通過C#創建一個抽象機制,不僅可以簡化開發,而且可以方便切換版本。我在嘗試了一段時間后,發現封裝的工作量很大,所以暫停了,待以后確實需要的時候再繼續。
目光轉到EasyUi,EasyUi傳說也是國人開發的,不過其官網卻是純英文。對於EasyUi,我幾年前也曾了解過,當時認為沒有源碼,萬一出現bug不是束手就擒嗎。雖然如此,我卻發現它越來越流行了,博客園搞框架的十有八九都是用的EasyUi,周邊也有很多公司在使用,甚至在招聘要求上,我也看到過要求有EasyUi的經驗。這說明EasyUi的穩定性還是有保證的,大家用都沒問題,難道我的運氣就那么背。
除了跟風以外,我選擇EasyUi還有幾個重要原因,首先是功能比較強大,重要的復雜組件和布局組件都提供了,雖然沒有Ext那么完善,但也基本夠用。其次是學習成本低,EasyUi也是基於jQuery,而且支持Html擴展。最后是官方文檔比較齊全。
可以看到,EasyUi的功能、文檔、易用性等介於Dwz與Ext之間。
還有一些朋友給我強力推薦Bootstrap,不過我感覺它有點輕量,管理系統需要更重口味的框架,開發類似會員后台的時候再考慮采用Bootstrap。
我學習EasyUi還不到一個月,很多東西仍處於摸索中,EasyUi雖然比較強大,但還是發現不少問題。
首先是它的方法調用方式讓人很郁悶。比如我現在要關閉一個窗口,需要這樣調用$('#xxx').dialog('close'),為什么不能這樣調用$('#xxx'). close ()。還好我主要使用Html擴展方式,手工編寫Js僅用來處理回調,這個問題可以忍忍。
其次發現不少小bug,比如多行文本框無法回車換行,時間控件在某些時候點擊時報對象為null的錯誤等等,我使用的是IE 11,估計作者還沒有對IE 11進行全面測試,希望能及時更新。
EasyUi雖然是一個比較完善的前端框架,但並不意味着不需要花任何力氣,你就可以開發出健壯的應用。下面討論兩個重要的設計決策。
SPA還是IFrame
SPA,全稱Single Page Applications, 即單頁應用程序。它的設計理念是僅在主框架界面使用一個完整的Html頁面,其它所有內容頁面都是Html片斷,沒有html、head、body這些標簽,主框架界面通過ajax的方式加載內容頁面。
SPA是正宗的Ajax應用模式,並且逐步成為Ajax應用的趨勢。它的優點顯而易見,所有東西都在同一個頁面,查找任何元素,直接用jQuery選擇器就行了。
任何事物都有兩面性,SPA也有很多缺點,最嚴重是命名沖突和兼容性。
對於同一個Html頁面,如果兩個元素的id出現重復,當你用css選擇器進行格式化,或用jQuery選擇器對其操作時,就會發生意想不到的情況。你會發現,操作某個內容頁面時,居然影響到另外一個不相干的內容頁。
jQuery解決這種命名沖突,是通過傳入一個額外的上下文對象,比如$(“#xx”,context)。Context代表某個內容頁,這樣就可以僅查找該內容頁的id,從而消除了命名沖突。
對於SPA,Dwz提供了天然的支持,它封裝了CRUD相關的所有操作,並提供了一個當前上下文context來保存當前操作的內容頁或彈出窗口。
雖然Dwz提供了SPA支持,但我在使用中,依然發現偶爾出現各內容頁互相影響的情況,為了防止命名沖突,我將id命名得很復雜,以減少沖突。
再看EasyUi,對於CRUD操作,只在官網找到一個很簡陋的Demo。仔細研究了Tabs等組件后,感覺EasyUi默認支持的是SPA模式,因為這些組件都沒有對IFrame進行支持。EasyUi既然支持的是SPA模式,但卻沒有做進一步的封裝,可以斷定,以SPA模式使用EasyUi,命名沖突是比較嚴重的。
還有一個頭痛的問題是兼容性,由於所有內容頁面在同一個Html中,如果某些頁面需要引用一個第三方插件,而這個插件不是基於jQuery的,或者jQuery版本不同,引入這些插件可能失敗。
基於以往的經驗,我決定不在管理系統這種復雜的應用中使用SPA,而是使用IFrame的方式加載內容頁。
由於EasyUi沒有對IFrame提供支持,當我向主界面的Tabs引入IFrame后,引發了一大堆連鎖問題,我花了大把時間終於把這些問題解決了,后面將用專門的文章來介紹碰到的障礙。
封裝有無必要
大部分使用Mvc的朋友,都是從Web Form轉過來的。所謂一遭被蛇咬,十年怕井繩,由於在Web Form上吃過過度封裝的苦頭,來到輕量級的Mvc世界,他們害怕服務器端的任何東西,只敢使用原生的html和js了。
Mvc提供了一套Html表單控件的封裝,比如文本框,@Html.TextBox( "id" ),它等價於<input type="text" name="id"/>。從這個簡單的例子,好像使用服務器端語法優勢並不明顯。但值得注意的是,服務器端語法能夠將DataAnnotations驗證自動轉化為jQuery驗證,這一點還是比較強大的。
對於簡單的html標簽,你是否使用mvc的服務端語法不是特別重要,但對於像Dwz或EasyUi這種Html擴展為主的前端框架就非常必要了。
EasyUi將每個組件的屬性都擴展到了Html標簽上,對於Html標簽,你還能指望代碼提示嗎?沒有代碼提示,就意味着你得隨時打開EasyUi的官網,以復制相關的屬性。當然你很多時候會自己手工輸入,你必須把這些API記得非常精確,如果多一個或少一個字符,你就會得到錯誤的結果。如果你沒有遵循敏捷開發的小步前進,而是把整個頁面輸入完成才開始運行,在密密麻麻的Html標簽中找出輸入錯誤的屬性也不是一件容易的事。
如果把EasyUi的屬性用C#封裝起來,由C#來輸出Html標簽,你就可以完全不再操心API的問題,所有的API只需在代碼提示中上下移動即可。可以看到,Web Form的很多思想其實是非常好的,比如用服務端代碼輸出客戶端代碼,你應該去其糟粕,取其精華。
對前端框架的封裝,真正強大的地方來自Lambda表達式。
從Lambda表達式中,你可以獲取到一些元數據信息,比如name、value、驗證信息,一個簡單的操作@Html.EasyUi().TextBox( t => t.Name ),可能設置了10幾個屬性,並且所有的屬性均來自服務器端,這樣維護也更加方便了,你不用來回修改客戶端代碼。
Lambda表達式還可以獲取到屬性的類型,這有什么用呢?當你寫上一句@Html.EasyUi().TextBox( t => t.XXX ),如果XXX是整型,文本框就自動轉成EasyUi的數字文本框,只能輸入數字,如果它是一個日期,文本框就顯示成一個日期控件。再比如@Html.EasyUi().Combox( t => t.XXX ),當它是布爾類型,就顯示一個是、否的下拉列表,如果它是一個枚舉就自動綁定一個枚舉值的下拉列表,這是不是比你手工輸入要強些呢。
結語
本文簡要介紹了我對幾個前端框架的認識,也說明了封裝的必要性。
由於我也是EasyUi初學者,我提供的Demo並不是一個可以直接使用的框架,不過作為學習范例,你可以把它作為你的應用程序框架的起點。
我后續文章會逐步介紹Demo中各構造塊的封裝和使用要點,所有代碼以我最新發放的Demo為准。
為了不沖淡本系列主題,我會專門為EasyUi框架的封裝創建一個系列。
對於EasyUi的封裝,我並沒打算封裝它的全部內容,畢竟我不是靠這個吃飯的,我僅在開發時碰到需求才會進行擴展,我的Demo會隨着我的開發逐步增強,我會定期發放最新源碼。
Demo已更新,需要的老規矩,點推薦,留Email,本次截止2015年1月28日15點。
另外大家短時間沒收到源碼不要着急,只要在規定時間內都可以拿到。
.Net應用程序框架交流QQ群: 386092459,歡迎有興趣的朋友加入討論。
謝謝大家的持續關注,我的博客地址:http://www.cnblogs.com/xiadao521/