不同框架實現(xiàn)的功能都是相似的野舶,只不過方法不同峦耘,這就為我們了解不同框架砌们,從一個框架向另一個框架學習提供了方便贩虾。比如說頁面之間的傳值催烘,看了vuex之后就在想angular實現(xiàn)類似的功能應該怎么做。
在angular中缎罢,實現(xiàn)controller之間傳值的方式大致有三種:
- 注入服務伊群。把需要共享的數(shù)據注冊為一個service,在需要的controller中注入策精。
- 基于事件舰始。利用angular中的事件機制,使用$on咽袜,$boardcast丸卷,$emit。
- 作用域繼承询刹。利用子controller控制父controller上的數(shù)據谜嫉。
在大項目中應該使用注入服務(推薦),小項目中可以使用基于事件的傳值(事件多了很繁瑣凹联,不利于高內聚沐兰、低耦合),作用域繼承不推薦(很大的局限性)蔽挠。
注入服務
在Angular里面僧鲁,services作為單例對象在需要到的時候被創(chuàng)建,只有在應用生命周期結束的時候(關閉瀏覽器)才會被清除象泵。而controllers在不需要的時候就會被銷毀了寞秃。所以在服務中生成一個對象,該對象就可以利用依賴注入的方式在所有的控制器中共享偶惠。
看個栗子春寿,先定義一個 service :
angular.module('demo')
.factory('Data', function(){
return {
name: 'htf'
};
})
頁面:
<div ng-controller="childCtrl1">
<h3>data in child controller 1 : {{data.name}}</h3>
<input class="form-control" type="text" ng-model="data.name">
</div>
<div ng-controller="childCtrl2">
<h3>data in child controller 2 : {{data.name}}</h3>
<input class="form-control" type="text" ng-model="data.name">
</div>
控制器:
.controller('childCtrl1', ['$scope', 'Data', function($scope, Data){
$scope.data = Data;
}])
.controller('childCtrl2', ['$scope', 'Data', function($scope, Data){
$scope.data = Data;
}])
這種方式適用于任何需要通信的 Controller 之間。
基于事件
Angular 為 $scope 提供了冒泡和隧道機制忽孽,$broadcast 會把事件廣播給所有子 Controller绑改,而 $emit 則會將事件冒泡傳遞給父 Controller,$on 則是 Angular 的事件監(jiān)聽函數(shù)兄一,利用這三者厘线,可以實現(xiàn)上下級和同級(需要構造一個共同的父級 Controller)之間的通信。
上下級之間
這種情況下比較簡單出革。
如果是子 Controller 往父 Controller 上發(fā)送事件(從作用域往上發(fā)送事件)造壮,使用 scope.$emit
$scope.$emit("someEvent", {});
如果是父 Controller 往子 Controller 上發(fā)送事件(從作用域往下發(fā)送事件),使用 scope.$broadcast
$scope.$broadcast("someEvent", {});
無論是 $emit 還是 $broadcast 發(fā)送的事件,都用 $scope.$on 接收:
$scope.$on("someEvent", function(event, data) {
// 這里取到發(fā)送過來的數(shù)據 data
});
同級之間
同級之間利用事件通信有兩種方法耳璧。一種是利用上下級之間事件傳播的變形成箫,另一種是借助 $rootScope 。
借助父 controller
先看第一種旨枯,在子 Controller 中向父 Controller 觸發(fā)一個事件蹬昌,然后在父 Controller 中監(jiān)聽事件,再廣播給子 Controller 攀隔,這樣通過事件攜帶的參數(shù)皂贩,實現(xiàn)了數(shù)據經過父 Controller,在同級 Controller 之間傳播昆汹。
但是要注意明刷,通過父 Controller 作為中介進行傳遞的話,子 Controller 觸發(fā)的事件名和父 Controller 廣播用的事件名不能一樣筹煮,否則會進入死循環(huán)。
看代碼:
<div ng-controller="outerCtrl">
<h3>data in outer controller: {{name}}</h3>
<div ng-controller="innerCtrl1">
<input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>
<div ng-controller="innerCtrl2">
<input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>
</div>
關鍵部分在控制器:
.controller('outerCtrl', ['$scope', function($scope){
$scope.name = 'htf';
$scope.$on('dataChanged', function(event, data){
$scope.name = data;
// 2. 父 Ctrl 監(jiān)聽到 dataChanged 時間后居夹,觸發(fā) changeData 事件
$scope.$broadcast('changeData', data);
})
}])
.controller('innerCtrl1', ['$scope', function($scope){
$scope.change = function(){
// 1. 子 Ctrl1 中數(shù)據改變之后觸發(fā) dataChanged 事件
$scope.$emit('dataChanged', $scope.name);
}
$scope.$on('changeData', function(event, data){
$scope.name = data;
})
}])
.controller('innerCtrl2', ['$scope', function($scope){
$scope.change = function(){
$scope.$emit('dataChanged', $scope.name);
}
// 3. 監(jiān)聽到 changeData 事件后败潦,改變子 Ctrl2 中 數(shù)據
$scope.$on('changeData', function(event, data){
$scope.name = data;
})
}])
借助 $rootScope
每個 Angular 應用默認有一個根作用域 $rootScope, 根作用域位于最頂層准脂,從它往下掛著各級作用域劫扒。
所以,如果子控制器直接使用 $rootScope 廣播和接收事件狸膏,那么就可實現(xiàn)同級之間的通信沟饥。
看栗子:
<div ng-controller="innerCtrlA">
<input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>
<div ng-controller="innerCtrlB">
<input class="form-control" type="text" ng-model="name" ng-change="change()">
</div>
控制器:
.controller('innerCtrlA', ['$scope', '$rootScope', function($scope, $rootScope){
$scope.change = function(){
// 廣播事件
$rootScope.$broadcast('nameChanged', $scope.name);
}
$rootScope.$on('nameChanged', function(event, data){
$scope.name = data;
})
}])
.controller('innerCtrlB', ['$scope', '$rootScope', function($scope, $rootScope){
$scope.change = function(){
$rootScope.$broadcast('nameChanged', $scope.name);
}
// 監(jiān)聽事件
$rootScope.$on('nameChanged', function(event, data){
$scope.name = data;
})
}])
作用域繼承
每個 Angular 應用默認有一個根作用域 $rootScope, 根作用域位于最頂層湾戳,從它往下掛著各級作用域贤旷。
通常情況下,頁面中 ng-model 綁定的變量都是在對應的 Controller 中定義的砾脑。如果一個變量未在當前作用域中定義幼驶,JavaScript 會通過當前 Controller 的 prototype 向上查找,也就是作用域的繼承韧衣。
頁面:
<div ng-controller="parentCtrl">
<p>data in parent controller : {{data.name}}</p>
<div ng-controller="childCtrl">
<input type="text" ng-model="data.name">
</div>
</div>
控制器:
angular.module('demo', [])
.controller('parentCtrl', ['$scope', function($scope){
$scope.data = {
name: 'htf'
}
}])
.controller('childCtrl', ['$scope', function($scope){
}])
以上是父 Controller 中的數(shù)據是引用類型的情況盅藻。如果父 Controller 中的數(shù)據是基本類型,改變子controller的值父controller的值不變畅铭,可通過 $scope.$parent.data 訪問氏淑。
很顯然,這種方式僅適用于父子級間 Controller 的通信硕噩。