公司项目开发用的是angularjs,关于事件通讯一直用的是EventBus,直到上周写一个小组件懒得引用EventBus时,想到用angularjs自带的事件通信时,结果很尴尬的忘记原生方法单词怎么写了....

可能现在记录这个真的算很晚了,包括对于显得有些老旧的angularjs,但我们学习的毕竟是思想,而非框架,所以还是独立一篇文章来聊聊angularjs中的事件通信$on,$emit与$broadcast。

一、为什么要用事件通信?

为什么要用事件通信?肯定要用啊,不用又解决不了问题,只能用事件通信维持生活这样子;在聊这个之前,先简单说说常见的跨作用域通信的几种场景。

问题情景一:父controller传子controller

我们在用angularjs日常开发中,跨作用域传值十分常见;比如父级作用域有一个属性,想跨作用域传递给子级,初学者可能习惯把这个属性绑在父级scope上,通过作用域继承让子级作用域可以直接使用。

<div ng-controller="parentCtrl">
<span>我是父作用域</span>
<div ng-controller="childCtrl">我是子作用域:{{name}}</div>
</div>
let parentCtrl = function ($scope) {
//父作用域定义name属性
$scope.name = "听风是风";
};
let childCtrl = function ($scope) {
//子作用域通过继承得到name属性
}; angular.module('myApp', [])
.controller("parentCtrl", ['$scope', parentCtrl])
.controller("childCtrl", ['$scope', childCtrl])

这是一种解决方法,但是将所有属性方法绑在scope上并不是很好的做法,这会让父子作用域的属性显得特别混乱。(先不谈controller as vm);

问题情景二:父作用域传值给子组件

这样的情况也十分常见,父作用域有个值在子组件中也需要使用,友好一点,我们通过bindings来解决这个问题:

<div ng-controller="parentCtrl as vm">
<ting-feng echo="vm.name"></ting-feng>
</div>
let parentCtrl = function () {
let vm = this;
vm.name = '听风是风';
};
angular.module('myApp', [])
.controller('parentCtrl', parentCtrl)
.component('tingFeng', {
template: '<div>我是子组件,我的名字是:{{self.echo}}</div>',
controllerAs: 'self',
bindings: {
echo: '<'
},
controller: function () {}
});

可以看到,这次没利用scope继承,使用了组件的属性也顺利完成了传值,问题不大。

问题情景三:异步跨作用域传值

有时候,我们在父作用域拿值是一个异步操作,我们不知道什么时候才能拿到值,这也决定了我们不知道什么时候才可以把这个值传给子作用域。

举个实际的例子,现在需求要做一个loading组件,页面初始化时显示loading,当请求完成,由父作用域通知loading组件隐藏loading效果。

很明显,此时通过bindings依旧能解决问题,难度不大。

上面三种情景均为父作用域传值给子作用域,我们现在反过来,通通由子作用域传父作用域,怎么解决?有什么一种方法能简单的的处理这三种情况呢?当然有,事件通信。

二、什么是事件通信?

angularjs的事件通信分为监听和派发两个重要阶段,有人(无中生有)对于监听和派发理解总是很模糊,其实不难理解。

大家在为dom绑定事件时一定用过事件监听addEventListener,比如:

document.getElementById("#div").addEventListener("click", function () {
console.log('我被点击啦');
});

在上述代码中,我们为一个id为div的元素添加了一个事件监听,它由click触发;当用户点击这个元素,就会执行事件监听的回调函数,也就是我们希望点击后执行的操作。

angularjs的事件通信其实和这个有些类似,我们总是先去监听一个东西,然后在满足某个情况下再去触发它,执行你想要的回调。

比如我在前面举的loading组件的例子,首先loading默认显示,并且监听控制是否显示的字段;当父作用域请求后台完毕,调用父传子的方法;子组件响应监听,执行回调拿到状态值,并修改loading的显示状态。我们拆分步骤:

1.loading子组件默认显示,监听isShow字段。

2.父作用域请求完毕,对应isShow字段派发事件。

3.子组件作响应监听,修改isShow,隐藏loading;

记住,永远都是先监听,后派发,这就像我们永远都是先声明函数,后调用它;如果你调用一个都为声明的函数,又怎么起作用域呢?

angularjs提供了用于监听的方法,还分别提供了父传子,子传父的方法,所以很好解决前面提到的子作用域希望传值给父作用域的情况。

三、angularjs事件通信$on,$emit,$broadcast方法

1.$broadcast方法

父作用域传给子作用域使用的方法,常见写法:

$scope.$broadcast(eventName,data);

eventName:父传子派发事件名称,与子作用域中的监听名保持一致,必写项。

data:需要传递的数据如果没有,可以不写。

注意:此方法一般写在某个触发条件中,比如请求完成后派发;被点击事件包裹,点击时派发,不能直接写;原因前提说过了,事件通信永远满足一点先监听后派发,你得保证监听在派发前初始化完成,这个涉及到了angularjs声明周期的问题,这里先不细谈。

2.$emit方法

子作用域传给父作用域使用的方法,常见写法:

$scope.$emit(eventName,data);

eventName:子传父派发事件名称,与父作用域中的监听名保持一致,必写项。

data:需要传递的数据,如果没有,可以不写。

3.$on方法

监听方法,与$emit,$broadcast配合使用,比如在父作用域派发给子,父作用域中使用$broadcast方法,那么对应的子作用域中就是用$on方法进行监听。常见写法:

$scope.$on('eventName', function (event, data) {
// do something...
});

eventName:监听名,与子传父,或父传子的事件派发名相同,必写。

event:有多个方法属性,这个对象使用不多。

currentScope:响应派发的当前作用域

targetScope:派发事件的原始作用域

name:事件名

defaultPrevented:默认为false

preventDefault:调用此方法defaultPrevented会变为true。

data:派发过来的数据,如果没有,可以不写。

四、一个例子

这里模拟一个前面提到的loading加载的例子,假设3秒后数据请求完成,则派发事件,通知子组件关闭loading显示。这里我们没有传递任何值给子组件,只是单纯的通知子组件要去做什么。

<div ng-controller="parentCtrl as self">
<on-loading></on-loading>
</div>
let parentCtrl = ($scope, $timeout) => {
//三秒后派发事件,通知loading组件关闭显示
$timeout(() => {
$scope.$broadcast('loadingEnd');
}, 3000);
};
angular.module('myApp', [])
.controller("parentCtrl", ['$scope', '$timeout', parentCtrl])
.component('onLoading', {
template: '<b>{{vm.num}}---{{vm.loading}}</b>',
controllerAs: 'vm',
controller: function ($scope, $interval) {
let vm = this;
//初始化loading状态,默认显示
vm.loading = 'loading进行中';
vm.num = 3;
$interval(() => {
vm.num ? vm.num-- : null;
}, 1000)
//监听,用于响应事件派发
$scope.$on('loadingEnd', () => {
vm.loading = 'loading已关闭';
});
}
});

大致效果如下:

我在前面说,公司对于angularjs事件通信使用的是EventBus,为什么呢?主要是因为angularjs并未提供兄弟之间通信的方法,而使用EventBus不用考虑这点,不管什么作用域,都能很便捷的通信。

我后面会专门花一篇文章介绍EventBus,加上最近和同学打算一起开个一个个人的小程序,可能未来时间也比较紧张,反正一定会更新,也是为了自己。

那么本文就写到这里了。

2019.9.17:解决父子组件异步传值,不用事件通信,只用ng-if也能搞定,有兴趣阅读 angularjs ng-if妙用,ng-if解决父子组件异步传值 这篇文章。

angularjs事件通信$on,$emit,$broadcast详解的更多相关文章

  1. angularjs 控制器、作用域、广播详解

    一.控制器 首先列出几种我们平常使用控制器时的几种误区: 我们知道angualrJs中一个控制器时可以对应不同的视图模板的,但这种实现方式存在的问题是: 如果视图1和视图2根本没有任何逻辑关系,这样& ...

  2. AngularJS 事件广播与接收 $broadcast,$emit,$on 作用域间通信 封装factory服务 发布订阅

    不同作用域之间通过组合使用$broadcast,$emit,$on的事件广播机制来进行通信. 一.说明 1.广播 $broadcast 说明:将事件从父级作用域传播至本作用域及子级作用域. 格式:$b ...

  3. AngularJS + CoffeeScript 前端开发环境配置详解

    AngularJS 号称 '第一框架' ('The first framework') 确实是名不虚传.由其从jQuery中完全转入AngularJS后就有无法离开他的感觉了.虽然AngularJS的 ...

  4. AngularJS入门教程之数据绑定原理详解

    这篇文章主要是写给新手的,是给那些刚刚开始接触Angular,并且想了解数据帮定是如何工作的人.如果你已经对Angular比较了解了,那强烈建议你直接去阅读源代码. Angular用户都想知道数据绑定 ...

  5. AngularJS 中的Promise --- $q服务详解

    先说说什么是Promise,什么是$q吧.Promise是一种异步处理模式,有很多的实现方式,比如著名的Kris Kwal's Q还有JQuery的Deffered. 什么是Promise 以前了解过 ...

  6. AngularJS表单验证实现方法详解

    本文主要是通过源码实例和大家分享AngularJS中的表单验证相关知识,希望通过本文的分享,对大家学习AngularJS有所帮助. 1.常规表单验证: 2.AngularJs中提供的表单验证实例. 实 ...

  7. Android随笔之——Android广播机制Broadcast详解

    在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理.这个广播跟我们传统意义中的电台广播有些相似之处.之所以叫做广播,就 ...

  8. ASP.NET页面事件:顺序与回传详解

    当页面被提交请求第一个方法永远是构造函数.您可以在构造函数里面初始一些自定义属性或对象,不过这时候因为页面还没有被完全初始化所以多少会有些限制.特别地,您需要使用HttpContext对象.当前可以使 ...

  9. js事件委托的方式绑定详解

    js事件绑定 事件绑定,这里使用了冒泡的原理,从点击的元素开始,递归方式的向父元素传播事件,这样做的好处是对于大量要处理的元素,不必为每个元素都绑定事件,只需要在他们的父元素上绑定一次即可,提高性能. ...

随机推荐

  1. CentOS自动化安装LAMP脚本

    #!/bin/bash #-- #blog:lizhenliang.blog.51cto.com ########## function ########## depend_pkg () { yum ...

  2. Java之字符编码和字符集

    什么是字符编码 计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字.英文.标点符号.汉字等字符是二进制数转换之后的结果.按照某种规则,将字符存储到计算机中,称为编码 .反之,将存储在计算 ...

  3. 第04组 Beta冲刺(2/4)

    队名:斗地组 组长博客:地址 作业博客:Beta冲刺(2/4) 各组员情况 林涛(组长) 过去两天完成了哪些任务: 1.分配展示任务 2.收集各个组员的进度 3.写博客 展示GitHub当日代码/文档 ...

  4. Centos7下Redis设置开机自启动服务

    有个同事说重启了服务器没有自启动redis,我看了一下,是以前手动编译安装的模式,没有配置开机启动的服务 这边做个笔记记录一下redis如何设置编译安装模式的开机自启动. 第一种方法: 1.编写red ...

  5. Spring 框架基础(03):核心思想 IOC 说明,案例演示

    本文源码:GitHub·点这里 || GitEE·点这里 一.IOC控制反转 1.IOC容器思想 Java系统中对象耦合关系十分复杂,系统的各模块之间依赖,微服务模块之间的相互调用请求,都是这个道理. ...

  6. Java描述设计模式(10):组合模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.文件系统 下图是常见的计算机文件系统的一部分. 文件系统是一个树结构,树上长有节点.树的节点有两种: 树枝节点 即文件夹,有 ...

  7. 基于Spring Boot+Spring Security+JWT+Vue前后端分离的开源项目

    一.前言 最近整合Spring Boot+Spring Security+JWT+Vue 完成了一套前后端分离的基础项目,这里把它开源出来分享给有需要的小伙伴们 功能很简单,单点登录,前后端动态权限配 ...

  8. C#_.NetFramework_Web项目_EXCEL数据导出

    [推荐阅读我的最新的Core版文章,是最全的介绍:C#_.NetCore_Web项目_EXCEL数据导出] 项目需引用NPOI的NuGet包: A-2:EXCEL数据导出--Web项目--C#代码导出 ...

  9. HTML元素分类 块级元素 内联元素 块级内联元素

    概述 HTML中存在许多元素,如<h1>,<p>,<a>,<block>,<image>,这些元素可分为三类,依次是块级元素,内联元素,块级 ...

  10. Unrecognized header format %

    <VirtualHost *:*> RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME} </ ...