在AngularJS中我们可以通过其事件系统完成Controller之间的通信。
AngularJS事件系统基于发布/订阅者模式 ,我们可以通过$scope
对应的$on
方法订阅
事件。用$broadcast``$emit
发布事件。
$broadcast
是自上而下的广播,当前$scope
发布事件后所有其后代$scope
都可以对事件作出响应。
$emit
是从下向上发射出的事件,当前$scope
发布事件只有它的祖先$scope
可以对事件作出响应,并且任一祖先$scope
都可以终结事件,阻止事件继续冒泡。
Angular为每个controller分配一个独立的$scope,controller之间的关系也对应着$scope之间的关系
$broadcast $emit $on 使用
我们创建了三个controller
:grandCtr
、parentCtr
、childCtr
。grandCtr和parentCtr订阅了childCtr发布的事件,childCtr订阅了parentCtr发布的事件。
- 事件的命名建议加上特定的前缀,因为事件可能跨函数乃至跨文件,避免混淆。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<body>
<div ng-app="app">
<div ng-controller="grandCtr">
<div ng-controller="parentCtr">
Parent name :
<input ng-model="name" type="text" ng-change="send();" />
<div ng-controller="childCtr">Child name :
<input ng-model="name" type="text" ng-change="send();" />
</div>
</div>
</div>
<script>
angular.module("app", []).controller("grandCtr", function($scope) {
$scope.$on("event_childName",
function(event, msg) {
console.log("Grand Receive:", msg);
});
}).controller("parentCtr", function($scope) {
$scope.name = "chenjy";
$scope.send = function() {
$scope.$broadcast("event_parentName", $scope.name);
}
$scope.$on("event_childName",
function(event, msg) {
console.log("Parent Receive:", msg);
});
}).controller("childCtr", function($scope) {
$scope.name = "tom";
$scope.send = function() {
$scope.$emit("event_childName", $scope.name);
}
$scope.$on("event_parentName",
function(event, msg) {
console.log("Child Receive:", msg);
});
});
</script>
</body>
</html>
我们也可以在parentCtr
终止事件的继续传播。
.controller("parentCtr", function($scope) {
$scope.name = "chenjy";
$scope.send = function() {
$scope.$broadcast("event_parentName", $scope.name);
}
$scope.$on("event_childName",
function(event, msg) {
console.log("Parent Receive:", msg);
// 阻止事件继续传播
event.preventDefault();
event.stopPropagation();
});
})
$rootScope.$emit 和 $rootScope.$on()
$rootScope
是所有$scope
的最顶层的祖先。所以我们可以通过将事件发布在$rootScope
上$rootScope.$emit
,然后直接在$rootScope
订阅事件。
这样比较高效的方式,因为$rootScope
已经是最顶层祖先不会继续冒泡,而且其他scope
对此一无所知。
但是
$rootScope.$broadcast+ $scope.$on
却是很浪费性能的方式,事件会从最顶层开始逐层传播
事件清除
使用$rootScope.$emit 和 $rootScope.$on()
我们可以很快速 高效的发布/订阅事件,但是由于事件是发布在$rootScope
上面的。当我们的子scope
销毁时事件并不会被清除。所以我们需要手动清除在$rootScope
上面发布的事件。
AngularJS并没有手动退订的事件。在我们订阅事件的时候会返回一个退订函数。我们只需要在需要退订的时候调用该函数即可
<body>
<div ng-app="app">
<div ng-controller="parentCtr">
Parent name :
<input ng-model="name" type="text" ng-change="send();" />
<button ng-click="desub()">Unsub</button>
<div ng-controller="childCtr">Child name :
<input ng-model="name" type="text" ng-change="send();" />
</div>
</div>
<script>
angular.module("app", []).controller("parentCtr", ["$scope","$rootScope",function($scope,$rootScope) {
var sub = $rootScope.$on("event_childName",
function(event, msg) {
console.log("Parent Receive:", msg);
});
$scope.name = "chenjy";
$scope.send = function() {
$scope.$broadcast("event_parentName", $scope.name);
}
$scope.desub = function(){
sub();
}
}]).controller("childCtr", ["$scope","$rootScope",function($scope,$rootScope) {
$scope.name = "tom";
$scope.send = function() {
$rootScope.$emit("event_childName", $scope.name);
}
$scope.$on("event_parentName",
function(event, msg) {
console.log("Child Receive:", msg);
});
}]);
</script>
</body>