本文透過實現兩個簡單的業務需求,探討AngularJS和傳統的JavaScript控制DOM實現方式的差別,並嘗試理解 MVW此類框架在流行的Web前端開發中的編程思想。
這個需求很常見,例如,一個兩級選單,在第一層選單項目點擊時候,對應的子選單項目應該顯示或隱藏。
jQuery的實作:
// javascript
$('li.parent_item').click(function(){
$(this).children('ul.child').toggle();
})
AngularJS的實作:
傳統操作DOM的方式,不再贅述。 AngularJS的實現,相對程式碼要精煉很多,只有HTML的版本即可。以上程式碼,用到了AngularJS這些知識點:
ng-click和ng-hide都是框架自帶的Directives(指令),前者相當於給li標籤提供了一個Event Handler,在該HTML元素( li)被點擊的時候,會執行hide_child = !hide_child這個Expression(表達式)。我們先來看看ng-hide這個指令,它會根據賦值的表達式結果(布林值)來控制該HTML元素是否要顯示(透過CSS實作)。也就是說,如果hide_child這個變數如果是true,那麼ul就會被隱藏,否則結果相反。
這裡hide_child其實是$scope上的一個變量,對它的值的變更,也可以用controller控制器包裝一個方法來實現,只不過現在的語句比較簡單,直接寫在了指令的賦值裡面。
透過以上簡單的程式碼分析,我們可以看到AngularJS兩個比較明顯的特點:
1.透過指令和表達式對DOM的操作進行了封轉,只需簡單的程式碼便可省去額外的JavaScript程式碼
2.指令和表達式的應用,只直接嵌套在HTML中的,這和jQuery推從的Unobtrusive JavaScript的程式碼風格有些背道而馳
我們先看另外一個需求,再詳細解釋上面的結論。
需求2:透過點選div,觸發選擇form中的一個radio button
傳統的HTML Form元素,在現今的行動裝置上,操作起來並不是十分友善。例如,Radio button單選框,在觸控螢幕上,需要精確的位置定位,才能控制這個組件,但手指定位又很粗糙。常見的做法,是增加一個對應的Label控件,但是文字本身佔屏比例也並不理想,而且也不具備明確的訊息傳達效果。所以,通常會間接操作一個區域比較大的div或li標籤。
jQuery的實作:
// javascript
$('li.selection').click(function(){
$(this).children('input[type="radio"]').click();
})
AngularJS 的實作:
在這個解決方案中,我們同樣沒有涉及到額外的JavaScript程式碼,並且多用了幾個指令。為了對比參照,我們只關心ng-click和ng-model這兩個指令的表達式。
我們先來看看input這個元素的ng-model指令,這裡賦值的意思是,我們把模板上的input和$scope.model物件的option屬性進行了關聯,深入了解數據綁定可以參考Data Binding。這種指定關聯,使得模板控制項直接和資料Model進行了綁定,並且這種綁定是雙向的。意味著,一旦使用者修改控制項中的值(勾選radio input),對應的Model物件就會重新賦值(model.option);同時,如果Model物件的值發生了變化,模板中的input控制項也會對應反映變化。而這一點,在上述jQuery的實作中,其實是沒有做到的。
所以,這裡透過AngularJS的資料綁定,點選li元素間接完成觸發input的流程是這樣子的:
1.點選li標籤,為model.option賦值;
2.修改了Model對象,定位到對應input控件(value的值為model.option那個);
3.啟動input控制項的checked屬性
透過以上兩個案例,我們對Web前端的操作有了新的認識。
首先,技術實現上,透過引入新的指令,表達式,資料綁定等概念,我們可以完全新的方式去操作DOM,而不僅僅局限在用戶和HTML組件交互操作上的JavaScript代碼的實現。這種思想的變化是巨大的。
從本世紀初,動態Web程式設計的興起開始,伺服器端的程式設計技術一直在改進。從一開始的CGI/PHP/ASP,由語言和平台產生了.NET vs. Java,開發效率和軟體過程促進了MVC框架/ORM/AOP等,性能和大數據帶來了NodeJS/NoSQL/Hadoop等,而瀏覽器前端的技術需求似乎沒有那麼激進過。一方面,透過伺服器端和資料庫,大部分B/S模型的業務需求都能滿足;再者,瀏覽器本身存在不同平台的差異性,對腳本語言和渲染技術的標準不相容,以及運算能力的欠缺和安全性的考慮。
在這種情況下,瀏覽器端的需求,大部分時候只需要考慮渲染頁面和簡單的使用者互動。 HTML/DOM加上JavaSript/CSS就這樣成就了前端的主要工作。所以,以前是沒有前端工作師,只需要Web設計師的。慢慢對前端的要求多起來,jQuery成為使用程度最高的一個JavaScript操作DOM的封裝函式庫。而在這個階段,jQuery/JavaScript的主要任務,仍然只是作為使用者瀏覽器終端呈現和互動的工具。
理解了jQuery的起源,我們不難發現,以前追求的一些規則,譬如Unobtrusive JavaScript,當時局限於實現的手段和方式,為了分離DOM和JavaScript代碼邏輯,我們優先選擇了維護性更高的方式。前端對JavaScript的需求加大之後,出現了許多MVC/MVP的前端框架,以及AngularJS所謂的MVW(Model-View-Whatever),JavaScript和DOM一刀切的方式發生了變化。原先我們考慮介面顯示和使用者互動的直接操作,現在我們有了客戶端的資料綁定,豐富的指令,依賴注入,等待我們的將是全新的程式設計模型和思維方式。