Angular $scope和$rootScope事件机制之$emit、$broadcast和$on
Angular按照发布/订阅模式设计了其事件系统,使用时需要“发布”事件,并在适当的位置“订阅”或“退订”事件,就像邮箱里面大量的订阅邮件一样,当我们不需要时就可以将其退订了。具体到开发中,对应着$scope和$rootScope的 $scope与$scope之间的关系,$scope与$rootScope之间的关系要理解Angular的事件机制,首先需要了解 <div ng-controller="ParentCtrl as parent">
{{ parent.data }}
<div ng-controller="SiblingOneCtrl as sib1">
{{ sib1.data }}
</div>
<div ng-controller="SiblingTwoCtrl as sib2">
{{ sib2.data }}
</div>
</div>
发布、订阅、退订
$scope.$broadcast('EVENT_NAME','Data to send');
$scope.$emit('EVENT_NAME','Data to send');
$scope.$on('EVENT_NAME',function(event,args) {
// balabala
});
Angular的退订事件有些奇怪,并没有类似于其他语言的 // 不要这样做
$scope.$off('EVENT_NAME');
事实上,Angular的事件退订方法隐藏在事件订阅里面:使用 // 订阅事件返回用于退订事件的函数
var deregister = $scope.$on('EVENT_NAME',args) {
// balabala
});
// 退订事件
deregister();
$broadcast相当于战斗机轰炸,$emit相当于射箭
具体到Angular上,即从一个 // 父$scope通过$broadcast发布事件
app.controller('ParentCtrl',['$scope',function($scope) {
$scope.$broadcast("parent",'Data to Send');
}])
//所有子$scope都可以通过$on订阅事件
.controller('SiblingOneCtrl',function($scope) {
$scope.$on("parent",'Data to Send') {
// balabala
});
}])
.controller('SiblingTwoCtrl','Data to Send') {
// balabala
});
}]);
而通过 // 子$scope通过$emit发布事件
app.controller('SiblingOneCtrl',function($scope) {
$scope.$emit("sib1",'Data to Send');
}])
// 父$scope通过$on订阅事件
.controller('ParentCtrl',function($scope) {
$scope.$on("sib1",'Data to Send') {
// balabala
});
}])
// 其兄弟$scope对其$emit的事件一无所知,所以不能订阅其事件
.controller('SiblingTwoCtrl',function($scope) {
// 不要这样做
$scope.$on("sib1",'Data to Send') {
// balabala
});
}]);
在 app.controller('ParentCtrl','Data to Send') {
// balabala
event.stopPropagation(); // 终止事件继续“冒泡”
});
}])
$rootScope的$broadcast和$emit上面说过 app.controller('SomeCtrl',['$rootScope',function($rootScope) {
$rootScope.$broadcast("rootEvent",'Data to Send');
// $rootScope也可以通过$on订阅从$rootScope.$broadcast发布的事件
$rootScope.$on("rootEvent",'Data to Send') {
// balabala
});
}])
// 所有$scope都能够通过$on订阅从$rootScope.$broadcast发布的事件
.controller('ParentCtrl',function($scope) {
$scope.$on("rootEvent",'Data to Send') {
// balabala
});
}])
.controller('SiblingOneCtrl','Data to Send') {
// balabala
});
}])
而 app.controller('SomeCtrl',function($rootScope) {
$rootScope.$emit("rootEvent",'Data to Send');
// 只有$rootScope可以通过$on订阅从$rootScope.$emit发布的事件
$rootScope.$on("rootEvent",'Data to Send') {
// balabala
});
}])
// $scope不能够通过$on订阅从$rootScope.$emit发布的事件
.controller('ParentCtrl',function($scope) {
// 不要这样做
$scope.$on("rootEvent",'Data to Send') {
// balabala
});
}]);
退订$rootScope上的订阅事件当使用 app.controller('SomeCtrl','$scope',function($rootScope,$scope) {
var deregister = $rootScope.$on("rootEvent",'Data to Send') {
// balabala
});
$scope.$on('$destory',function() {
deregister(); // 退订事件
});
}])
那通过 事件命名的建议在开发中,对于变量的命名、函数的命名、文件的命名都有一定的规范,既要保证可读性,也需要保证无混淆性。在Angular的事件机制中,因为事件可能会跨函数,甚至可能跨文件,所以对于事件名一定要保证唯一性,所以建议事件名都加上特定的前缀,以便区分。如下几个例子: $scope.$emit('trash:delete',data);
$scope.$on('trash:delete',function (event,data) {...});
$scope.$broadcast('trash:clear',data);
$scope.$on('trash:clear',data) {...});
结语Angular的事件机制很智能,而且一般来说总能符合我们的预期,但是如果不能深入理解其背后的机制,可能会踏入某些深坑,本文尝试说明Angular的事件机制,如果有理解不正确的地方,请留言告知。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |