惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyberwarzone
Cyberwarzone
Vercel News
Vercel News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
aimingoo的专栏
aimingoo的专栏
B
Blog RSS Feed
A
About on SuperTechFans
T
The Blog of Author Tim Ferriss
爱范儿
爱范儿
腾讯CDC
S
SegmentFault 最新的问题
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Hacker News
The Hacker News
J
Java Code Geeks
大猫的无限游戏
大猫的无限游戏
B
Blog
IT之家
IT之家
Spread Privacy
Spread Privacy
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
Cisco Blogs
Recent Announcements
Recent Announcements
H
Hacker News: Front Page
AI
AI
I
InfoQ
H
Heimdal Security Blog
T
Threatpost
Cisco Talos Blog
Cisco Talos Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
I
Intezer
W
WeLiveSecurity
SecWiki News
SecWiki News
MongoDB | Blog
MongoDB | Blog
宝玉的分享
宝玉的分享
博客园 - 【当耐特】
云风的 BLOG
云风的 BLOG
T
Threat Research - Cisco Blogs
V2EX - 技术
V2EX - 技术
N
News and Events Feed by Topic
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
O
OpenAI News
阮一峰的网络日志
阮一峰的网络日志
T
Troy Hunt's Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
雷峰网
雷峰网
T
Tor Project blog
有赞技术团队
有赞技术团队
Schneier on Security
Schneier on Security
Last Week in AI
Last Week in AI

博客园 - sunjie

关于C#中async/await中的异常处理(上) 入门教程: JS认证和WebAPI ASP.NET Core 之 Identity 入门(二) 在Visual Studio 2017中使用Asp.Net Core构建Angular4应用程序 .Net Core+Angular Cli/Angular4开发环境搭建教程 简单易用的.NET免费开源RabbitMQ操作组件EasyNetQ解析 Razor - 模板引擎 / 代码生成 - RazorEngine 一个简易的反射类库NMSReflector 发布 Ionic iOS 企业级应用 AngularJS中的Provider们:Service和Factory等的区别 Ionic开发实战 Entity Framework 5.0 Code First全面学习 6个强大的AngularJS扩展应用 使用npm安装一些包失败了的看过来(npm国内镜像介绍) 自己家里搭建NAS服务器有什么好方案? 自己动手制作CSharp编译器 使用Visual Studio Code搭建TypeScript开发环境 Office web app server2013详细的安装和部署 谈谈家庭装修中强电回路设计以及电线空开配套
Angular $scope和$rootScope事件机制之$emit、$broadcast和$on
sunjie · 2016-12-22 · via 博客园 - sunjie

Angular按照发布/订阅模式设计了其事件系统,使用时需要“发布”事件,并在适当的位置“订阅”或“退订”事件,就像邮箱里面大量的订阅邮件一样,当我们不需要时就可以将其退订了。具体到开发中,对应着$scope和$rootScope的$emit$broadcast$on方法。本文介绍Angular的事件机制,包括$scope和$rootScope处理事件上的异同,$broadcast、$emit和$on的使用方式及他们区别等内容。

$scope与$scope之间的关系,$scope与$rootScope之间的关系

要理解Angular的事件机制,首先需要了解$scope$scope之间的关系以及$scope$rootScope之间的关系。$rootScope是唯一真神,是万域起源,是所有$scope的最终祖先。而$scope$scope之间可能的关系包括父子关系和兄弟关系。还记得controller之间的关系吗,Angular为每个controller分配一个独立的$scope,controller之间的关系也对应着$scope之间的关系:

<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>

发布、订阅、退订

$broadcast$emit用于发布事件,他们将事件名称和事件内容发布出去,就像是高考榜单一样,事件名称相当于考生的名字,而事件内容相当于考生的成绩等信息:

$scope.$broadcast('EVENT_NAME', 'Data to send');
$scope.$emit('EVENT_NAME', 'Data to send');

$on用于订阅事件,事件名称是订阅的唯一标识,每个考生看榜单时都要寻找自己的名字,然后根据自己的成绩等信息决定下一步应该报考什么学校:

$scope.$on('EVENT_NAME', function(event, args) {
    

Angular的退订事件有些奇怪,并没有类似于其他语言的$off方法,所以不要想当然的按照如下方式进行事件的退订操作:

// 不要这样做
$scope.$off('EVENT_NAME');

事实上,Angular的事件退订方法隐藏在事件订阅里面:使用$on订阅事件时会返回一个函数,而此函数就是用来退订事件的方法,就像是考生看到了自己的成绩后禀告父母大人,“商量着”选取学校填报志愿,而此志愿单就是结束整个高考榜单的结束:

// 订阅事件返回用于退订事件的函数
var deregister = $scope.$on('EVENT_NAME', function(event, args) {
    

$broadcast相当于战斗机轰炸,$emit相当于射箭

$broadcast$emit都用于发布事件,但从名字就可以看出他们的不同点:$broadcast是自上而下的广播,所有能听到的都可以对其进行反应。而$emit是自下而上的射箭,只有在箭矢的轨迹上才能对其做出反应。

具体到Angular上,即从一个$scope上通过$broadcast发布的事件,他的所有后代$scope都可以对此事件做出响应:

// 父$scope通过$broadcast发布事件
app.controller('ParentCtrl', ['$scope', function($scope) {
    $scope.$broadcast("parent", 'Data to Send');
}])

而通过$emit发布的事件,只有他的祖先$scope可以做出响应,并且其中任一祖先都可以将此事件终结掉,不让其继续传播:

// 子$scope通过$emit发布事件
app.controller('SiblingOneCtrl', ['$scope', function($scope) {
    $scope.$emit("sib1", 'Data to Send');
}])

$emit发布事件的响应道路上,其任一祖先如果感觉不再需要此事件了,就可以通过如下方式终结此事件:

app.controller('ParentCtrl', ['$scope', function($scope) {
    $scope.$on("sib1", function(event, 'Data to Send') {
        

$rootScope的$broadcast和$emit

上面说过$rootScope是所有$scope的最终祖先,所以通过$rootScope$broadcast发布的事件可以被所有$scope接收到,包括$rootScope

app.controller('SomeCtrl', ['$rootScope', function($rootScope) {
    $rootScope.$broadcast("rootEvent", 'Data to Send');

    

$rootScope$emit就有些怪异了,按照上面的描述,$rootScope是没有祖先的,所以我们可能会想到其$emit会没有任何作用,但事实并不如此:$rootScope.$emit发布的事件,只能通过$rootScope.$on订阅,而其他$scope对此一无所知:

app.controller('SomeCtrl', ['$rootScope', function($rootScope) {
    $rootScope.$emit("rootEvent", 'Data to Send');

    
  •  

退订$rootScope上的订阅事件

当使用$rootScope.$on订阅事件时,需要手动退订事件,一般在其所处$scope$destory事件中退订:

app.controller('SomeCtrl', ['$rootScope', '$scope', function($rootScope, $scope) {
    var deregister = $rootScope.$on("rootEvent", function(event, 'Data to Send') {
        
  •  

那通过$scope.$on订阅的事件呢?一般不需要手动退订,因为Angular会帮我们退订,但是如果需要自己控制何时退订事件,也可以通过上述方式进行退订。

事件命名的建议

在开发中,对于变量的命名、函数的命名、文件的命名都有一定的规范,既要保证可读性,也需要保证无混淆性。在Angular的事件机制中,因为事件可能会跨函数,甚至可能跨文件,所以对于事件名一定要保证唯一性,所以建议事件名都加上特定的前缀,以便区分。如下几个例子:

$scope.$emit('trash:delete', data);
$scope.$on('trash:delete', function (event, data) {...});

$scope.$broadcast('trash:clear', data);
$scope.$on('trash:clear', function (event, data) {...});