Angular $scope和$rootScope事件机制之$emit、$broadcast和$on

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) {
    // balabala
});

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

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

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

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

// 退订事件
deregister();

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

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

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

// 父$scope通过$broadcast发布事件
app.controller(‘ParentCtrl‘, [‘$scope‘, function($scope) {
    $scope.$broadcast("parent", ‘Data to Send‘);
}])
//所有子$scope都可以通过$on订阅事件
.controller(‘SiblingOneCtrl‘, [‘$scope‘, function($scope) {
    $scope.$on("parent", function(event, ‘Data to Send‘) {
        // balabala
    });
}])
.controller(‘SiblingTwoCtrl‘, [‘$scope‘, function($scope) {
    $scope.$on("parent", function(event, ‘Data to Send‘) {
        // balabala
    });
}]);

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

// 子$scope通过$emit发布事件
app.controller(‘SiblingOneCtrl‘, [‘$scope‘, function($scope) {
    $scope.$emit("sib1", ‘Data to Send‘);
}])
// 父$scope通过$on订阅事件
.controller(‘ParentCtrl‘, [‘$scope‘, function($scope) {
    $scope.$on("sib1", function(event, ‘Data to Send‘) {
        // balabala
    });
}])
// 其兄弟$scope对其$emit的事件一无所知,所以不能订阅其事件
.controller(‘SiblingTwoCtrl‘, [‘$scope‘, function($scope) {
    // 不要这样做
    $scope.$on("sib1", function(event, ‘Data to Send‘) {
        // balabala
    });
}]);

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

app.controller(‘ParentCtrl‘, [‘$scope‘, function($scope) {
    $scope.$on("sib1", function(event, ‘Data to Send‘) {
        // balabala
        event.stopPropagation(); // 终止事件继续“冒泡”
    });
}])

$rootScope的$broadcast和$emit

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

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

    // $rootScope也可以通过$on订阅从$rootScope.$broadcast发布的事件
    $rootScope.$on("rootEvent", function(event, ‘Data to Send‘) {
        // balabala
    });
}])
// 所有$scope都能够通过$on订阅从$rootScope.$broadcast发布的事件
.controller(‘ParentCtrl‘, [‘$scope‘, function($scope) {
    $scope.$on("rootEvent", function(event, ‘Data to Send‘) {
        // balabala
    });
}])
.controller(‘SiblingOneCtrl‘, [‘$scope‘, function($scope) {
    $scope.$on("rootEvent", function(event, ‘Data to Send‘) {
        // balabala
    });
}])

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

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

    // 只有$rootScope可以通过$on订阅从$rootScope.$emit发布的事件
    $rootScope.$on("rootEvent", function(event, ‘Data to Send‘) {
        // balabala
    });
}])
// $scope不能够通过$on订阅从$rootScope.$emit发布的事件
.controller(‘ParentCtrl‘, [‘$scope‘, function($scope) {
    // 不要这样做
    $scope.$on("rootEvent", function(event, ‘Data to Send‘) {
        // balabala
    });
}]);

退订$rootScope上的订阅事件

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

app.controller(‘SomeCtrl‘, [‘$rootScope‘, ‘$scope‘, function($rootScope, $scope) {
    var deregister = $rootScope.$on("rootEvent", function(event, ‘Data to Send‘) {
        // balabala
    });

    $scope.$on(‘$destory‘, function() {
        deregister(); // 退订事件
    });
}])

那通过$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) {...});

原文地址:https://www.cnblogs.com/huangwentian/p/8334085.html

时间: 2024-08-26 19:48:25

Angular $scope和$rootScope事件机制之$emit、$broadcast和$on的相关文章

ng $scope与$rootScope的关系

$scope与$rootScope的关系:①不同的控制器之间 是无法直接共享数据②$scope是$rootScope的子作用域对象$scope的id是随着控制器的加载顺序依次递增,$rootScope的id是1 ③不同控制器之间如何通信??1.借助于$rootScope2.既然子作用域对象可以调用父作用域对象的值或者方法,就可以通过控制器之间的嵌套来实现通信3.事件父->子$scope.$broadcast('eventName',args) 子->父$scope.$emit('eventNa

Angularjs中的事件广播 —全面解析$broadcast,$emit,$on

Angularjs中不同作用域之间可以通过组合使用$broadcast,$emit,$on的事件广播机制来进行通信 介绍: $broadcast的作用是将事件从父级作用域传播至子级作用域,包括自己.格式如下:$broadcast(eventName,args) $emit的作用是将事件从子级作用域传播至父级作用域,包括自己,直至根作用域.格式如下:$emit(eventName,args) $on用于在作用域中监控从子级或父级作用域中传播的事件以及相应的数据.格式如下:$on(event,dat

[AngularJS面面观] 12. scope中的watch机制---第三种策略$watchCollection

如果你刚刚入门angular,你或许还在惊叹于angular的双向绑定是多么的方便,你也许在庆幸未来的前端代码中再也不会出现那么多繁琐的DOM操作了. 但是,一旦你的应用程序随着业务的复杂而复杂,你就会发现你手头的那些angular的知识似乎开始不够用了.为什么绑定的数据没有生效?为什么应用的速度越来越慢?为什么会出现莫名其妙的infinite digest异常?所以你开始尝试进阶,尝试弄清楚在数据绑定这个现象后面到底发生了什么. 相信能顺着前面数十篇文章看到这里的同学们,一定对angular是

QT开发(六十三)——QT事件机制分析

QT开发(六十三)--QT事件机制分析 一.事件机制 事件是由系统或者QT平台本身在不同的时刻发出的.当用户按下鼠标.敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件在对用户操作做出响应时发出,如键盘事件等:另一些事件则是由系统自动发出,如计时器事件. 事件的出现,使得程序代码不会按照原始的线性顺序执行.线性顺序的程序设计风格不适合处理复杂的用户交互,如用户交互过程中,用户点击"打开文件"将开始执行打开文件的操作,用户点击"保存文件"将开始执

Qt事件机制概览

Qt事件机制概览 Qt事件机制概览 消息循环 Qt事件循环 简介 QEventLoop 跨线程的信号和槽与事件循环 模态窗口 Native widget or Alien widget 创建Native widget 创建QApplication的message-only窗口 派发事件的公共基础方法 source code QApplication的创建过程 QWidget native QWidget 的创建过程 普通native widget回调过程 QApplication的message

JavaScript事件机制

<script type="text/javascript" src="http://runjs.cn/gist/2zmltkfa/all"></script> [前端培养-作业01]javascript事件机制 1.javascript事件模型 2.e.target与e.currentTarget是干什么的? 3.preventDefault与stopPropagation是干什么的 4.什么是dispatchEvent? 5.说一说事件代

Android-- Android事件机制之二:onTouch详解

Android事件机制之二:onTouch详解 在其中对OntouchEvent中的总结中,不是很具体.本文将主要对onTouch进行总结. onTouch是Android系统中整个事件机制的基础.Android中的其他事件,如onClick.onLongClick等都是以onTouch为基础的. onTouch包括从手指按下到离开手机屏幕的整个过程,在微观形式上,具体表现为action_down.action_move和action_up等过程. onTouch两种主要定义形式如下: (1)在

聊一聊Android的事件机制

侯 亮 1概述 在Android平台上,主要用到两种通信机制,即Binder机制和事件机制,前者用于跨进程通信,后者用于进程内部通信. 从技术实现上来说,事件机制还是比较简单的.从大的方面讲,不光是Android平台,各种平台的消息机制的原理基本上都是相近的,其中用到的主要概念大概有: 1)消息发送者: 2)消息队列: 3)消息处理循环. 示意图如下: 图中表达的基本意思是,消息发送者通过某种方式,将消息发送到某个消息队列里,同时还有一个消息处理循环,不断从消息队列里摘取消息,并进一步解析处理.

Nginx处理stale事件机制分析

Nginx为提高效率采用描述符缓冲池(连接池)来处理tcp连接,一个连接对应一个读事件和一个写事件,nginx在启动的时候会创建好所用连接和事件,当事件来的时候不用再创建,然而连接池的使用却存在stale事件的问题,以下将详细分析Nginx是如何处理stale事件的,该问题涉及到epoll.Nginx连接与事件的相关知识. 1      Epoll的实现原理 epoll相关的系统调用有:epoll_create, epoll_ctl和epoll_wait.Linux-2.6.19又引入了可以屏蔽