AngularJS 是製作 SPA(單頁面應用程式)和其它動態Web應用最廣泛使用的框架之一。我認為程式設計師在使用AngularJS編碼時有一個大的列表點應該記住,它會以這樣或那樣的方式幫助到你。下面是一些我遵守的最佳實踐建議,同時也想推薦給你們。 我堅信有更多的功能也應該是這份列表的一部分,我邀請你們都來提建議或者在下面評論,從而使這個成為完整的最佳實踐指南。
一、依賴注入:
1. 依賴注入是AngularJS框架最好的特性之一,我們應該經常使用它。當我們需要對我們的應用程式進行測試用例覆蓋時,它將真正的起到幫助。
2. 為依賴提供別名,這樣他們不會在(JS程式碼)壓縮過程中重新命名,因為在AngularJS依賴是通過命名來實現的(注:AngularJS通過控制器建構函式的引數名字來推斷依賴服務名稱的)。
1 2 3 4 5 6 |
angular.module(‘myApp’).controller('MyController', ['$scope', 'MyService',function($scope, MyService) { // controller logic } ]); |
二、作用域
1. 在templates(模板)中scope(作用域)按只讀對待。這就是說即使AngularJS允許我們在templates中編寫程式碼修改scope,我們必須非常謹慎或者就不應該做。
2. 在controllers(控制器)中scope按只寫對待。這就是說一個controllers負責使用另一個元件,就像一個服務,獲取template 將要顯示的資料和把資料寫到scope的一個物件中。
- 作為一個經驗法則,我們必須總是在繫結時使用”.“。這就是說我們應該繫結到scope的物件,而不是直接的屬性,否則可能會在子$scope導致意外的行為,因為$scope基於Java-script的原型繼承機制。
- 下面的程式碼我們可以看到,superhero是scope上一個通過Superhero服務返回的物件,同時相同的物件被用來繫結在view(檢視)上。
1 2 3 4 5 |
<div class="form-group"> <label class="control-label" for="name">Super Power</label> <div class="controls"> <input type="text" data-ng-model="superhero.superPower"> </div> |
1 2 3 |
$scope. superhero = Superheros.get({ superheroId: $stateParams.superheroId )}; |
- Scope 的目的是引用 model,而不是成為 model。
- Model是我們的JavaScript物件
三、驗證
1. 在form(表單)標籤中使用“novalidate”
屬性來使用 AngularJS驗證同時關閉HTML5驗證。
1 |
<form name="reviewForm" ng-controller="ReviewController as reviewCtrl" ng-submit="reviewCtrl.addReview(product)" novalidate> |
2. 我們可以使用angular classes(css類)來改變可見性和驗證控制元件的狀態。
1 2 3 4 5 6 |
.ng-valid.ng-dirty{ border-color: #FA787E; } .ng-invalid.ng-dirty{ border-color: #FA787E; } |
四、記憶體 – 任務管理
- AngularJS在銷燬一個scope和把一個scope從它的父級移除之前會廣播一個$destroy事件。監聽這個事件對清理任務和資源是至關重要的,否則可能會繼續消耗記憶體或CPU。總是註冊‘destroy‘事件來刪除任何易於記憶體洩漏的程式碼。
作為一個例子,下面的控制器在1秒的間隔不斷更新一個mode(模型)l值,這些更新將永遠持續,即使在controller對應view消失了或者scope從父級上移除。如果使用者來回導航到一個view來載入這個controller,每次導航將新增另一個永遠執行的計時器。
1 2 3 4 5 6 7 8 9 |
module.controller("MyController", function($scope, $timeout) { var onMyTimeout = function() { $scope.value += 1; $timeout(onMyTimeout, 100); }; $timeout(onMyTimeout, 100); $scope.value = 0; }); |
監聽$destroy事件是停止計時器的一個機會。一種方法是取消由$timeout返回的promise(承諾)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
module.controller("TestController", function($scope, $timeout) {var onTimeout = function() { $scope.value += 1; timer = $timeout(onTimeout, 100); }; var timer = $timeout(onTimeout, 100); $scope.value = 0; $scope.$on("$destroy", function() { if (timer) { $timeout.cancel(timer); } }); }); |
五、事件 頂級作用域
1. 我們應該只在當前螢幕的單頁面應用程式的控制器中使用scope 事件進行通訊。如果我們只需要共享資料,那麼我們應該考慮使用Services(服務)。
2. 當觸發事件時,除非我們需要把事件通知到我們整個應用程式裡的所有單個scope,否則我們不需要在$rootScope觸發事件。如果我們只需要為子scope觸發,則在當前的scope上$broadcast事件。父scope使用$emit獲取當前scope事件。這也將縮短事件傳播,而不是經過整個自上而下的流動。
3. Services 是在$rootScope監聽事件獲取通知的不二選擇。這是因為services在我們的應用程式中只初始化一次,並沒有獲取它們自己的scope ,這將是很好。
4. 通常我們不應該在$rootScope註冊事件監聽(除了service)。這是導致AngularJS應用程式產生bug的一個普遍原因。這是因為當我們在一個controller 的$scope上新增一個事件監聽,而controller 被銷燬(我們導航離開頁面,或關閉一個部分),監聽同樣被銷燬。當我們將它新增到$rootScope,同時導航離開一個controller,監聽會保留並保持活動和觸發。所以我們必須從$rootScope手動取消監聽,或者為了安全乾脆就不在$rootScope上新增監聽。但是如果我們必須為$rootScope新增一個事件,不要忘記在controller的scope中將其清除。
1 2 3 4 5 6 |
<strong> </strong> var myEventHandler = $rootScope.$on('MyEvent', ‘My Data’); $scope.$on('$destroy', function() { myEventHandler(); }); |
5. 如果我們知道只有一個監聽器,而且你已經遇到了。我們可以通過在傳遞給事件監聽函式的事件物件上呼叫event.stopPropagation()來停止進一步的事件傳播。
六、構建業務邏輯
1. Controllers 不應該引用DOM,而只是包含行為,使用Directives (指令)做DOM操作。
2. Services應該對view邏輯獨立.
3. 不要與HTML打架,而是通過Directives擴充套件。
4. 最好是使用模組化的資料夾結構,這樣我們可以建立可重用的/可分發的元件。
七、通用規則
1. 對images使用ng-src 替代src。
2. 使用promise 來處理回撥。AngularJS已經為它暴露了“$q”服務。許多AngularJS services返回promises:$http, $interval, $timeout。
3. 不要壓縮angular.min.js 因為AngularJS團隊已經通過預定義設定壓縮了angular檔案,如果我們再壓縮可能會產生破壞。所以直接使用。
4. 如果template (模板)快取是必需的,使用$templateCache快取html template。
5. 總是把第三方API的回撥包裹到$apply,用來通知AngularJS關於環境的變化。
6. 如果我們不想讓使用者在AngularJS載入之前顯示HTML ,使用ng-cloak directive。
1 2 3 4 5 |
<div class="session ng-cloak">..............content............</div> .ng-cloak { /* this will change to block when scope and angular is ready */ display:none; } |
7. 為了阻止任何衝突,不要在我們自己的directives裡使用“ng”字首。建立你的自定義的。最好使用<my–component> ,因為 <my:component>在IE有時出錯。
1 2 |
<my-component> <my:component> |
8. 在應用程式中為全域性相關的事件使用$broadcast() , $emit() 和 $on()(比如使用者身份驗證或應用程式關閉)。如果我們需要特定於模組,服務或小部件的事件,我們應該選擇Services,Directive Controllers等。
9. 不要使用自動關閉標籤,因為有些瀏覽器不喜歡他們。使用“<product-title></product-title >”而不是“<product-title/>”。