AngularJS:何時應該使用Directive、Controller、Service?

AngularJS是一款非常強大的前端MVC框架。同時,它也引入了相當多的概念,這些概念我們可能不是太熟悉。(譯者注:老外真謙虛,我大天朝的碼農對這些概念那是相當熟悉啊!)這些概念有:

Directive(指令)

Controller(控制器)

Service (服務)

下面我們逐個來看這些概念,研究一下為什么它們會像當初設計的那樣強大,同時研究一下為什么我們要以那樣的方式去使用它們。我們從Service開始。

SERVICES(服務)

如果你已經使用過AngularJS,你可能已經遇到過Service這個概念了,簡而言之,Service就是【單例對象】在AngluarJS 中的一個別名。這些小東西(指單例對象)會被經常傳來傳去,保證你每次訪問到的都是同一個實例,這一點和工廠模式不同。基于這種思想,單例對象讓我們可以 實現一些相當酷的功能,它可以讓很多controller和directive訪問內部的數值。在#angularjs 頻道(譯者注:指的是原作者自己的博客頻道)里面這也是非常常見的問題之一,那就是在應用中的不同代碼塊之間如何共享數據?我們來看這個問題。

我們首先來創建一個module(模塊),本文中的所有代碼都會用到這個module。

varmodule= angular.module( "my.new.module", [] );

下一步,我們來創建一個新的service(服務)。假設我們上面的這個module是用來管理圖書的。所以,這里我們來創建一個Book service,然后把一個JSON對象數組添加到這個serice中,這些對象代表很多book數據。

module.service('Book', ['$rootScope',function( $rootScope ){varservice = { ? ? ?books: [ ? ? ? ?{ title:"Magician", author:"Raymond E. Feist"}, ? ? ? ?{ title:"The Hobbit", author:"J.R.R Tolkien"} ? ? ?], ? ? ?addBook:function( book ){ ? ? ? ?service.books.push( book ); ? ? ? ?$rootScope.$broadcast('books.update'); ? ? ?} ? }returnservice;}]);

這是一個非常簡單的service(有時候這樣就夠你用了)。我們這里正在做的事情就是在管理一個book 數組,同時還帶有一個addBook方法,在有需要的時候可以添加更多書籍。addBook方法還會在application上廣播一個事件,告訴所有正 在使用我們的service的人,數組已經被更新了,從而讓它們自己也做一些刷新操作。現在,我們要做的就是把這個service傳遞給各種 controller、directive、filter,或者其它任何需要它的東西---然后它們就可以訪問service中的這些方法和屬性了。好, 我們來動手。

varctrl = ['$scope','Book',function( scope, Book ){ ? scope.$on('books.update',function( event ){ ? ? scope.books = Book.books; ? ? scope.$apply();//注意,原文這里少了這一行}); ? ?scope.books = Book.books; }]; module.controller("books.list", ctrl );

同樣非常簡單。我們上面所做的就是為我們的module創建了一個新的controller。在創建的時候把$scope provdier和我們自己的Book service傳遞給了它。能明白我們在干嘛嗎?我們把前面創建的Book service中的books數組賦給了controller內部的局部scope對象。很酷,對吧?

好,這里的核心問題是什么呢?我們節省了一些時間,并且在controller上創建了一個數組。對---我們確實這樣做了。這樣做確實也為我們節 約了一點時間---但是如果我們要在其它地方處理這些書籍信息應該怎么辦呢?通過scope來維護數據是非常粗暴的一種方式。由于其它 controller、directive、model的影響,scope很容易就會崩潰或者變臟。它很快就會變成一團亂麻。通過一種集中的途徑(在這里 就是service)來管理所有書籍數據,然后通過某種方式來請求修改它,這樣不僅僅會更加清晰---同時當應用的體積不斷增大的時候也更加容易管理。最 后,它還可以讓你的代碼保持模塊化(這也是Angular很擅長的一件事情)。一旦你在其它項目中需要用到這個service,你沒有必要在scope、 controller、filter等等東西里面到處去查找相關的代碼,因為所有東西都在service里面!

好。那么我們什么時候應該使用service呢?答案是:無論何時,當我們需要在不同的域中共享數據的時候。另外,多虧了Angular的依賴注入系統,實現這一點是很容易并且很清晰的。

CONTROLLERS(控制器)

我們再來看控制器!除非你曾經使用過前端MVC,否則從服務端MVC的思維模式轉向客戶端MVC的思維模式就如同一次腦筋急轉彎。為什么會這樣呢? 這是因為,雖然在前端開發中controller實現了非常類似的功能,但是它同時還會實現一些與服務端controller非常不同的功能。在 Angular中,controller自身并不會處理"request",除非它是用來處理路由(route)的(很多人把這種方式叫做創建route controller---路由控制器),更明確地說,尤其是你的應用里面那些作為界面的一部分的controller,它們只會管理非常小的一段代碼。

controller應該純粹地用來把service、依賴關系、以及其它對象串聯到一起,然后通過scope把它們關聯到view上。如果在你的 視圖里面需要處理復雜的業務邏輯,那么把它們放到controller里面也是一個非常不錯的選擇。回到我們前面的這個books例子,我實際上并沒有什 么東西需要添加到controller里面。

但是Kirk(譯者注:指本文原作者),如果我要add一本書籍應該怎么辦呢?我應該在controller上面新增一個方法來處理這件事情嗎? 不,原因在下面解釋。因為它是DOM交互/操作的一部分。所以請把它放到directive(指令)里面。怎么做呢?很高興你能問出這個問題。

DIRECTIVES(指令)

到目前為止,在我們所編寫的大量AngularJS應用中,應用中最主要的復雜部分都在directive(指令)中。有一個強大的工具可以用來操 作和修改DOM,它也是我們這里需要討論的內容。我們來提供一個按鈕,用戶通過它可以向service里面添加一本圖書,以這一功能來結束此文。

一個常見的反模式(按照本人愚見)是在controller里面添加DOM交互代碼。Angular對directive的定義是一段代碼片段,你 可以用它來操作DOM,但是我覺得directive也是進行用戶交互的很好選擇。我們來擴展前面的例子,為用戶提供一個按鈕,通過這個按鈕可以向 service里面添加一本書籍。

module.directive("addBookButton", ['Book',function( Book ){return{ ? ? ? ?restrict:"A", ? ? ? ? ? ?link:function( scope, element, attrs ){ ? ? ? ? ? ?element.bind("click",function(){ ? ? ? ? ? ? ? ?Book.addBook( { title:"Star Wars", author:"George Lucas"} ); ? ? ? ? ? ?}); ? ? ? ?} ? ?}}]);

很簡單的東西。我們創建了一個指令,它的核心目的是簡單地向books列表中添加一本書籍,books已經注冊在了我們的Book服務中。我們來把這個指令應用到我們的視圖中。

Add book

如你所見,我們僅僅把指令當作一個元素屬性來使用。每次點擊這個按鈕的時候,它都會把《Star Wars》(《星球大戰》)這本書添加到我們的Book service中去。簡單、輕松、模塊化---并且易復用。好了,我們為什么不直接在控制器上面添加一個addBook之類的方法呢,比如說就像下面這 樣:

$scope.addBook =function(){ ? ? Book.addBook( { title:"Star Wars", author:"George Lucas"} ); };

這樣我們也能獲得同樣的結果,對吧?是的,確實如此---但是這樣做會帶來一個重大的問題。一旦我需要在其它地方添加書籍,我必須拷貝這份代碼(非 常un-DRY!)(譯者注:DRY---Dont Repeat Yourself,貌似是Ruby所倡導的一個重要的編碼原則。),或者進行重構(重構本身并不是什么不好的的事情)。通過直接構建一個指令的方式,我們 以后就沒有必要擔心這種事情了---同時下次再需要實現相同功能的時候完全不需要花任何時間。通過構建指令的方式來進行DOM交互和修改,隨著業務需求的 不斷介入,我們就可以立即騰出手來處理復雜性不斷增加的應用了。這是相當不錯的一件事情,因為它保證了我們可以更少地和自己的實現打架,并且可以一直編寫 DRYer code。

Angular的模塊依賴哲學無疑讓它成為了一款非同凡響的框架。它讓我們能夠以這樣一種方式來編寫我們的前端代碼:我們不會干翻自己,也不會干翻框架---這可能是它最強大的力量。

希望我已經充分說明了你應該在何時何地使用這幾個Angular概念,從而能夠更好地編寫你自己的代碼。

本文大漠窮秋譯,原文鏈接:

http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內容