AngularJS:什麼時候應該使用Directive、Controller、Service?

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

  • Directive(指令)
  • Controller(控制器)
  • Service (服務)

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

SERVICES(服務)

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

 

        咱們首先來建立一個module(模塊),本文中的全部代碼都會用到這個module。數組

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

        下一步,咱們來建立一個新的service(服務)。假設咱們上面的這個module是用來管理圖書的。因此,這裏咱們來建立一個Book service,而後把一個JSON對象數組添加到這個serice中,這些對象表明不少book數據。app

module.service( 'Book', [ '$rootScope', function( $rootScope ) {
      var service = {
      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' );
      }
   }
   return service;
}]);

        這是一個很是簡單的service(有時候這樣就夠你用了)。咱們這裏正在作的事情就是在管理一個book 數組,同時還帶有一個addBook方法,在有須要的時候能夠添加更多書籍。addBook方法還會在application上廣播一個事件,告訴全部正 在使用咱們的service的人,數組已經被更新了,從而讓它們本身也作一些刷新操做。如今,咱們要作的就是把這個service傳遞給各類 controller、directive、filter,或者其它任何須要它的東西---而後它們就能夠訪問service中的這些方法和屬性了。好, 咱們來動手。框架

var ctrl = [ '$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,它們只會管理很是小的一段代碼。lua

        controller應該純粹地用來把service、依賴關係、以及其它對象串聯到一塊兒,而後經過scope把它們關聯到view上。若是在你的 視圖裏面須要處理複雜的業務邏輯,那麼把它們放到controller裏面也是一個很是不錯的選擇。回到咱們前面的這個books例子,我實際上並無什 麼東西須要添加到controller裏面。spa

        可是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服務中。咱們來把這個指令應用到咱們的視圖中。

<button add-book-button>Add book</button>

        如你所見,咱們僅僅把指令看成一個元素屬性來使用。每次點擊這個按鈕的時候,它都會把《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概念,從而可以更好地編寫你本身的代碼。

相關文章
相關標籤/搜索