AngularJS中使用Directive、Controller、Service

寫在前面:本文適合AngularJS新手,老手略過。

AngularJS是一款非常強大的前端MVC框架。同時,它也引入了相當多的概念,這些概念我們可能不是太熟悉。

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

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

本文系轉載,點我看原文,版權歸原作者所有。

SERVICES 服務

如果你已經使用過AngularJS,你可能已經遇到過Service這個概念了,簡而言之,Service就是 單例對象 在AngularJS中的一個別名。這些小東西(指單例對象)會被經常傳來傳去,保證你每次訪問到的都是同一個實例。這一點和工廠模式不同。

基於這種思想,單例對象讓我們可以實現一些相當酷的功能,它可以讓很多controllerdirective訪問內部的數值。

我們來看一個非常常見的問題,那就是在應用中的不同代碼塊之間如何共享數據?

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

1
2
// 創建一個angularjs的module
var module = angular.module('my.new.module', []); // 這裏的第二個空數組參數一定要有

下一步,我們來創建一個新的service(服務)。假設我們上面的這個module是用來管理圖書的。所以,這裏我們來創建一個Book Service,然後把一個JSON對象數組添加到這個service中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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(有時候這樣的service其實就夠用了)。我們這裏正在做的事情就是在管理一個book數組,同時還帶有一個addBook方法,在有需要的時候可以添加更多的書籍。addBook方法還會在application上廣播一個事件,告訴所有正在我們服務Book的人,數組已經被更新了,從而讓它們自己也做一些刷新操縱。

現在,我們要做的就是把這個service傳遞給各種controller、directive、filter,或者其他任何需要它的東西,然後它們就可以訪問service中提供的這些方法和屬性了。

下面我們聲明一個controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
module.controller('books.list', [
'$scope',
'Book',
function($socpe, Book) {
// books.update事件監聽
$scope.$on('books.update', function(event) {
$scope.books = Book.books;
$scope.$apply();
});

$scope.books = Book.books;
}
]);

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

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

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

CONTROLLERS 控制器

我們再來看控制器!

除非你曾經使用過前端MVC,否則從服務端MVC的思維模式轉向客戶端MVC的思維模式就如同一次腦筋急轉彎。爲什麼會這樣呢?

這是因爲,雖然在前端開發中controller實現了非常類似的功能,但是它同時還會實現一些與服務端controller非常不同的功能。在 Angular中,controller自身並不會處理request,除非它是用來處理路由(route)的(很多人把這種方式叫做創建route controller,路由控制器),更明確地說,尤其是你的應用裏面那些作爲界面的一部分的controller,它們只會管理非常小的一段代碼。

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

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

DIRECTIVES 指令

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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服務中。我們來把這個指令應用到我們的視圖中。

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

如你所見,我們僅僅把指令當作一個元素屬性來使用。每次點擊這個按鈕的時候,它都會把《Star Wars》(《星球大戰》)這本書添加到我們的Book service中去。簡單、輕鬆、模塊化,並且易複用。

好了,我們爲什麼不直接在控制器上面添加一個addBook之類的方法呢,比如說就像下面這樣:

1
2
3
4
5
6
$scope.addBook = function() {
Book.addBook({
title: "Star Wars",
author: "George Lucas"
});
};

這樣我們也能獲得同樣的結果,對吧?是的,確實如此,但是這樣做會帶來一個重大的問題。

一旦我需要在其它地方添加書籍,我必須拷貝這份代碼(非常un-DRY!,DRY—-Dont Repeat Yourself,貌似是Ruby所倡導的一個重要的編碼原則。),或者進行重構(重構本身並不是什麼不好的的事情)。通過直接構建一個指令的方式,我們以後就沒有必要擔心這種事情了,同時下次再需要實現相同功能的時候完全不需要花任何時間。通過構建指令的方式來進行DOM交互和修改,隨着業務需求的不斷介入,我們就可以立即騰出手來處理複雜性不斷增加的應用了。這是相當不錯的一件事情,因爲它保證了我們可以更少地和自己的實現打架,並且可以一直編寫DRYer code

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

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

英文原文

End! All rights reserved @gejiawen.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章