摘要:這使得許多人并未真正了解的模板,而認為只是提供了一堆內置指令并可用于文件。是個對于模板很重要的指令,它是基本的條件表達,滿足條件時則存在,不滿足則不存在。則是另一重要指令,能循環創建。
作為最流行的MVVM(Model-View-View-Model)框架之一,相信大部分前端對AngularJS都不會陌生,我也一樣久仰大名。不得不說,AngularJS所帶來的改變是巨大的,被稱為未來瀏覽器的模式一點也不為過,尤其是思維上的轉變。
作為一個常年揮舞著jQuery去指揮無窮無盡的DOM的前端,初次接觸AngularJS是有困難的,許多先賢警告我們不要在AngularJS中使用jQuery,不是沒有道理的。即使AngularJS中帶有jQlite對象,也僅僅是為了彌補一些地方AngularJS的局限性。AngularJS操作UI的方式與jQuery有著極大區別,在深入學習之后,我漸漸的發現了這點。過去使用jQuery的前端就像一個操縱提線木偶的傀儡師,而手握AngularJS的前端簡直是不折不扣的魔法師。前端開發者不再需要根據數據去改變DOM,然后填入數據,我們所要做的僅僅是決定數據的表現形式后等待數據的注入。文檔流中的元素就像活過來了一樣,根據數據表現出了對應的樣子。
這一切的核心除了匪夷所思的DOM監聽機制,還有就是AngularJS的模板(template)以及其中多不勝數的內置指令(directive)了。因此,我將在本文中談談AngularJS的模板以及其思維模式。
AngularJS模板和EmberJS的模板相比更為普通一些,仍然是HTML格式的文件。這使得許多人并未真正了解AngularJS的模板,而認為AngularJS只是提供了一堆內置指令并可用于HTML文件。不過就先來說說這些內置指令吧,模板后面再詳細討論。
ngIf是個對于模板很重要的指令,它是基本的條件表達,滿足條件時則存在,不滿足則不存在。通過它可以輕松的讓模板基于數據呈現不同結構。另外它會形成獨立Scope,這也是其與ngShow/ngHide的區別之一。如果ngIf出現太多可能會導致頁面渲染速度降低,此時可以選擇ngSwitch來代替它,不過此時最好先一下檢查你的邏輯。
ngRepeat則是另一重要指令,能循環創建DOM。可以說只要數據中有數組等結構,這一指令就必不可少。配合$index等索引變量,ngRepeat可以創造出多種形式的列表。還有ngRepeatStart/ngRepeatEnd可以將2個元素之間的內容循環創建,但我很少使用它們,因為這種混合多種元素的HTML結構不太好。
ngClass是樣式層面上的主要指令,它的值可以是存放class名的變量,也可以是帶有條件的對象。如此可以通過表達式來選擇需要的class,以呈現不同的樣式。ngHide與ngShow其實就是特殊的ngClass,ng-hide="[expression]"相當于ng-class="{"hide": [expression]}"。
這些基本的指令構成了一套很有效的模板邏輯,我們可以消除掉各種HTML的重復性代碼,還能在單個模板中呈現出無數的形式。但我不贊成將大段的HTML做成partial或directive并通過switch或if來選擇性呈現,因為模板應該是可復用的組件,而不是帶有邏輯的路由。
真正的頁面只有一個AngularJS的主旨即快速創建單頁面應用,所謂單頁面就是說真正的頁面只有一個,其中變化的只是模板和數據。但許多習慣于傳統Web的開發人員往往找不到單頁面的感覺,自然而然的將模板當作了以往的HTML頁面,然后根據AngularJS的路由一一對應到模板。這是時常發生的情況,即使是在開發的中途也可能轉入這個誤區,因為模板的邏輯難以劃分,還有被控制器牽連進去的,最后只能讓每個路由多帶帶使用對應模板。
模板不是頁面,不應該和路由有任何邏輯關系,它關心的應該僅僅是數據呈現結構。所謂的數據呈現結構是說數據需要以何種方式呈現,比如列表、統計圖、詳情或分頁等,而不是數據結構。它往往依賴于HTML結構,所以當HTML的結構不夠表意時,模板的劃分也會跟著變得困難。一個模板就是一個對象,不屬于它的東西,無論多麻煩,即使HTML可以放在一起,也一定要排除在外,無論封裝成directive還是partial,或者分離出去與之變成平級關系。
模板也不應該關心數據的內容,即使兩個路由中顯示的數據內容完全不一樣,但顯示結構一樣或類似,模板就應該利用自身的邏輯在注入數據后呈現對應的內容。但值得注意的是,其自身邏輯應該判斷數據本身而不是引用控制器的邏輯,也就是說模板要有自身的邏輯,不應該將頁面邏輯混合散落在模板和控制器中。那么如何做才好呢,簡而言之就是UI邏輯和業務邏輯的分離,模板中應該只存在UI邏輯。我們應該封裝模板,像黑盒一樣,無論控制器有什么業務邏輯,都不應該干涉UI邏輯。
比如ngIf指令可以使用表達式,我們應該利用數據本身達到邏輯表達,而不是依賴于控制器中依賴于業務邏輯的變量,比如使用data.length > 0而不是hasData。這看起來是一樣的,但其實區別很大,前者將具體邏輯放到了模板中,當數據為空時不顯示,而后者則把邏輯拋給了控制器。這樣就不僅僅是邏輯放置在哪的問題了,這是違背MVVM框架初衷的。因為當data為空后,控制器必須之前在監聽data,并將hasData設為false,而這些事應該交由AngularJS在數據綁定時自動完成。所以如果實在分不清什么邏輯是UI邏輯要放在模板中,什么邏輯是業務邏輯該放在控制器中,那就遵循一個原則,能利用Angular性能時就利用,不要做AngularJS已經做過的事。
Scope屬于誰?其實這是思維方式的轉變,所以誤入歧途是不可避免的,而其中最多的誤解在于Scope。Scope本身是作為在控制器中的模板作用域,實際效果就是Scope上的屬性在模板中可以直接使用,無論是在花括號還是Angular的表達式中,比如指令中。但開發人員很容易被其表面所迷惑,將其當作傳統后端模板的變量來使用,更有甚者發明了$scope.vm作為ViewModule來使用,但其實Scope本身就應該是ViewModule。其原因還是在于思維,不同于傳統后端的模板變量,Scope是依賴注入到控制器的,也就是說Scope不屬于控制器,而屬于模板。很明顯在模板中將不需要Scope這一名稱來指明,因為所有變量都是Scope的。
Scope屬于控制器或模板有區別嗎?有而且非常大。當Scope一片空白的來到控制器時,我們自然而然的認定這樣一個原先空空的變量肯定是被控制器創造出的,然后在模板中被使用。但我們換個角度想想,如果模板先定義了它需要的Scope的結構,而后控制器僅僅只是按照預先的定義插入對應的數據,Scope的結構是不是明顯屬于模板。仔細想想其實很好理解,模板和任何控制器組合都是這套Scope結構,而控制器脫離了該模板Scope就變了,而且模板不用的東西,控制器放到Scope中也等于沒有。也就是說,往往我們先定義了控制器才開始編輯模板,自然認為Scope是控制器創建好給模板用的,但如果我們先創建模板,控制器其實只能按照模板中規定的結構來填入數據。而這就像是Java中的接口一樣,模板定義好接口,然后控制器只要滿足這些填入自己的數據,就能在頁面上獲得需要的東西,而且同樣它們都是一對多的關系。也許有人會說,那也存在同樣的邏輯和結構卻需要不同顯示方式的情況。其實,這僅僅是表現形式的改變,數據呈現結構卻沒有發生本質上的改變,一個列表,無論是列、行還是格子都仍然是一個表格,模板應該用ngRepeat將其呈現,然后就是CSS的事情了。當你遇到無法使用CSS轉變呈現方式的時候,首當其沖的應該考慮一下,是否HTML寫的不好,不夠靈活,沒有語義化呢。
當我們完成這樣的思維轉變,模板將不再依賴于控制器,它也可以完整的自我封裝起來。這樣做的好處顯而易見,HTML的代碼將有巨大的精簡,重復的代碼消失的無影無蹤,因為當它們重復時就可以形成一個獨立的模板,模板可以套模板,它們還可以互相引用。但要注意循環引用,比如a引用了b而b又引用了a。如此CSS的重構也將變得更加簡單,此時考慮使用OOCSS等提高CSS復用性將變得易如反掌。另外如果某個模板具有關聯十分緊密的復雜邏輯還可以打包做成指令,這樣模板的邏輯將更加的強大。
命名轉變思維要做到這樣的思維轉變其實是很難的,不過有一個小技巧可以借以完成這樣的轉變,那就是命名。當設計模板Scope結構時,我們可以更多的考慮這樣的一個結構中某數據是什么。在控制器中,也許是一組系統管理員的數據,我們可以命名為admins,也許是一組用戶數據users,又或者是一組讀者數據reader,還可能是采購員buyer。不過等等,一旦使用了這之中的某個命名,模板就會和控制器綁在一起,你無法為其他的數據使用該模板,而恰恰對于設計統一性來說,這些數據又很可能會放在同種結構之中,也許僅僅是顏色或標題的差異。
此時還能做什么,復制一份相同的模板然后選擇另外的命名?完全錯誤,我們應該抽象它們,它們都是一類數據,列表list。就像之前我說的,設計模板時僅僅應該關心其數據表現結構,它就是一個列表,列表的數據內容完全不會影響到結構。無論是users還是buyer,都可以放入一個list模板中。這是非常重要的,一個長期和數據庫打交道的后端,慣性思維會將user和users歸為一類,并認為admins和users是完全不同的。但是到了UI層面,這些顯而易見的規則已經不適用了,users和admins都是list,而admin和user都是object。如果你擔心不同數據類型需要的UI表現不一樣,那就應該先考慮CSS實現兼容各種形式,其次是考慮嵌入一些不同的模板或指令來實現差異化,而不是直接復制兩個模板。
總之,使用AngularJS一定不要過多考慮流程,而要考慮UI本身,我覺得這有點像面向對象的思維方式,UI既對象。利用AngularJS的監聽機制讓數據驅動模板產生交互。甚至我還經常利用JavaScript中Object的引用類型特性,使一些關聯的數據之間也能產生數據與視圖之間的關聯,這樣連通UI與數據和數據與數據之后就不用再管UI了,只需要操作數據即可,UI自然會表現出應有的狀態。
博客原文地址
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87596.html
摘要:前后端的界限是按照瀏覽器和服務器的劃分。前后端彼此互不關聯。關于作者本文部分圖片段落參考文章實踐中的前后端分離。淘寶前后端分離實踐本文源碼詳見服務端代碼。 一、起源 (故事純屬虛構,如有雷同,純屬巧合)傳說在很久很久以前,我們有志之士有了個創業的想法,于是乎開始了自己的創業之夢,但是人手不足啊,于是乎所有角色老子一個人全包了: Roles: PM, DBA, RD, FED, Des...
摘要:前后端的界限是按照瀏覽器和服務器的劃分。前后端彼此互不關聯。關于作者本文部分圖片段落參考文章實踐中的前后端分離。淘寶前后端分離實踐本文源碼詳見服務端代碼。 一、起源 (故事純屬虛構,如有雷同,純屬巧合)傳說在很久很久以前,我們有志之士有了個創業的想法,于是乎開始了自己的創業之夢,但是人手不足啊,于是乎所有角色老子一個人全包了: Roles: PM, DBA, RD, FED, Des...
摘要:本書的這一部分將為隨后的章節打下基礎,會涵蓋模板,模塊化,和依賴注入。本書的小例子中我們會使用未經壓縮的,開發友好的版本,在的上。作用域也可以針對特定的視圖來擴展數據和特定的功能。 上一篇:【譯】《精通使用AngularJS開發Web App》(一) 下一篇:【譯】《精通使用AngularJS開發Web App》(三) 原版書名:Mastering Web Application D...
摘要:模塊和依賴注入細心的讀者可能已經發現了,到目前為止所用到的例子都是使用的全局的構造函數來定義控制器的。這非常的簡單,只需使用如下參數來調用即可控制器的名字字符串類型控制器的構造函數全局定義的控制器構造函數只適用于快速示例和原型開發。 上一篇:【譯】《精通使用AngularJS開發Web App》(三) 下一篇: 書名:Mastering Web Application Develop...
閱讀 1854·2023-04-25 23:28
閱讀 563·2023-04-25 22:49
閱讀 2241·2021-09-27 13:34
閱讀 5158·2021-09-22 15:09
閱讀 3609·2019-08-30 12:52
閱讀 2740·2019-08-29 15:26
閱讀 659·2019-08-29 11:12
閱讀 2190·2019-08-26 12:24