轉載請寫明來源地址:http://blog.csdn.net/lastsweetop/article/details/56285838 理解Components
在AngularJS中,Component是一種特殊的directive,它的配置更簡單一些,非常適合組件化的app架構。使用web組件和使用Angular風格的app架構使得編寫app更為簡便。
Component的優點: 比普通directive要簡單很多 更加嚴謹,更加正常化 更加適合組件化架構 component更容易升級到angular2
不使用Component的情況 需要在編譯階段和預連結階段執行的directive,因為Component這時還不可用 當你需要directive才有定義的選項時,如priority, terminal, multi-element 當你需要directive由屬性,css的class而不是元素觸發時 Components的建立和配置
Components由angularjs的module使用.component()方法註冊。這個方法接受2個參數: Component的名稱(字串類型) Component的設定物件(注意,和.directive()不一樣,不是一個Factory 方法而僅僅是個設定物件)
heroApp.html:
<!DOCTYPE html><html><head> <meta charset="uft-8"/> <title></title></head><script src="script/angular.min.js"></script><body ng-app="heroApp"><div ng-controller="MainCtrl as ctrl"> <b>Hero</b><br> <hero-detail hero="ctrl.hero"></hero-detail></div></body><script> angular.module('heroApp', []).controller('MainCtrl', function MainCtrl() { this.hero = { name: 'Spawn' }; }); function HeroDetailController() { } angular.module('heroApp').component('heroDetail', { templateUrl: 'heroDetail.html', controller: HeroDetailController, bindings: { hero: '=' } });</script></html> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
heroDetail.html:
<span>Name: {{$ctrl.hero.name}}</span> 1 1
Directive和Component之間的定義比較
| 屬性 |
Directive |
Component |
| bindings |
No |
Yes (binds to controller) |
| bindToController |
Yes (default: false) |
No (use bindings instead) |
| compile function |
Yes |
NO |
| controller |
Yes |
Yes (default function() {}) |
| controllerAs |
Yes (default: false) |
Yes (default: $ctrl) |
| link functions |
Yes |
No |
| multiElement |
Yes |
No |
| priority |
Yes |
No |
| replace |
Yes (deprecated) |
No |
| require |
Yes |
Yes |
| restrict |
Yes |
No (restricted to elements only) |
| scope |
Yes (default: false) |
No (scope is always isolate) |
| template |
Yes |
Yes, injectable |
| templateNamespace |
Yes |
No |
| templateUrl |
Yes |
Yes, injectable |
| terminal |
Yes |
No |
| transclude |
Yes (default: false) |
Yes (default: false) |
組件化app架構
如前所述,component使得使用組件化架構構建app更為容易,除此之外component還具備的能力具體如下: Component只能控制它自己的視圖和資料:Component不會修改它自身scope之外的任何資料或DOM。通常情況下,AngularJS中可以通過scope繼承和watch可以修改任何地方的資料,這確實很實用,但是也會導致很難明確哪個部分對修改資料負責。這就是為什麼Component使用隔離範圍,也因此無法進行所有scope的操作。
Component有明確定義的公用api-輸入輸出:隔離範圍並不是全部,因為AngularJS是雙向繫結的。如果你傳一個對象到組件中,類似bindings: {item: '='},然後修改對象的屬性,修改會反映到它的父組件中。但是對於component來說,component確實只是修改了它自己的scope內的資料。這樣就很清晰的得知什麼資料什麼時候被修改。就此,component遵循一些簡單的約定:
輸入需要使用<和@綁定。<符號在1.5之後表示單向綁定,和=不同的是,它綁定的屬性在component的scope哪不會被watch,這意味著你可以在component的scope內給屬性設定一個新的值,它並不會更新父scope裡的值。但是如果父scope和component的scope引用的是同一個對象,比如你在component修改對象的屬性或者數組中的元素,這種改變仍然會反映到父scope。因此在<綁定後不要在component內修改對象的屬性和數組的元素。當輸入的值是字串時可以使用@綁定,特別是在綁定的值不會更改的時候。
bindings: { hero: '<', comment: '@'} 1 2 3 4 1 2 3 4
輸出使用&進行綁定,綁定的函數將作為component事件的回呼函數
bindings: { onDelete: '&', onUpdate: '&'} 1 2 3 4 1 2 3 4
在不操作輸入資料的情況下,component可以調用相應的輸出事件改變輸出資料。比如刪除,並不是hero自己刪除自己,而是通過相應的事件把自己傳給父component
<!-- note that we use kebab-case for bindings in the template as usual --><editable-field on-update="$ctrl.update('location', value)"></editable-field><br><button ng-click="$ctrl.onDelete({hero: $ctrl.hero})">Delete</button> 1 2 3 1 2 3
這樣,父component來決定事件執行什麼(刪除item還是更新屬性)
ctrl.deleteHero(hero) { $http.delete(...).then(function() { var idx = ctrl.list.indexOf(hero); if (idx >= 0) { ctrl.list.splice(idx, 1); } }); } 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
Component有明確定義的生命週期:每個組件都可以實現lifecycle hooks,這些方法會在component生命週期的相應的點被調用,可以實現的hook方法如下: $onInit() - 在element上的所有controller構造和所有的綁定初始化之後,在element之上首碼&的函數連結之前,每一個controller調用這個鉤子方法。這是個給controller寫一些初始化方法的好地方 $onChanges(changesObj) - 當單向綁定更新時調用,changesObj是一個hash索引值對,key是已被修改的綁定屬性的name,value是一個對象,格式是{ currentValue, previousValue, isFirstChange() },使用這個hook可以只觸發組件內的更新,比如複製綁定屬性的對象以防止它被外部意外更新 $doCheck() - 在每一個digest迴圈被調用,提供了一個機會可以在資料更改時驗證或者做一些操作。任何你希望進行的操作(比如對更改的響應)都必須通過這個hook調用。當$onChanges被調用時,實現這個hook沒什麼作用。比如,比如你想實現一個深度的equal函數檢查,或者檢查一個Date對象時,他將會非常有用,因為這是AngularJS的變化檢測器檢測不到這個變化,自然$onChanges也不會被調用。這個hook不包含任何參數,因此,如果想要檢測變化,你需要儲存之前的值,然後和現在的值進行比較。