NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

Angular 的模块间通信

  • 2017-03-15
  • 本文字数:3552 字

    阅读完需:约 12 分钟

关键点

  • Angular 是用基于模块的应用程序架构构建的,所以是有可能在模块之间传输数据的;
  • 你可以通过 @Input() 把数据传入子模块;
  • 你可以通过 @Output() 从子模块捕获数据;
  • 随着应用程序的发展,父子模块之间的通信会越来越困难;
  • 你可以通过 ngrx 之类的方法用外部数据库来构建大规模应用程序;

模块是 Angular 的构建单元,Angular 应用程序的所有可视化元素也是由模块构建的。基于模块的架构的一个重大好处在于,与 JavaScript 函数非常相像,如果一块代码变得过于复杂,或者承担了过多责任,你就可以把它打散,让每一段代码都只做一件事。

也就是说,当我们把模块拆散成更小的模块时,我们就要确保它们可以把数据传来传去。到那时候,恰当地模块间通信机制就成了我们应用程序的基础,可以让所有的数据都保持同步状态。幸运的是,Angular 给我们提供了这样的工具来完成这件事。

如上图所示,我们可以在 AppComponent 之下构建整个应用程序,但这样做会让那个模块承担过多的责任。在基于模块的架构里,大家公认比较好的实践是把模块拆散,好让它们都只承担单一的责任。

将数据传给模块

在 Angular 中,当一个父模块要把数据传入子模块中时,我们可以使用 @Input。假设我们现在要构建一个程序,在页面上显示评论。AppComment 将负责加载所有的评论内容,我们会把每条评论数据都发送给评论模块。

我们将调用:

复制代码
@Input() comment

把一个 comment 参数传入子模块。下面就是整块模块代码的样子:

复制代码
@Component({
selector: 'comment',
templateUrl: './comment.component.html',
styleUrls: ['./comment.component.css']
})
export class CommentComponent {
@Input() comment;

现在我们可以从我们代码其它部分调用这个模块,并把它需要的数据传入这个模块了。这块代码看起来会像这样:

复制代码
<comment [comment]="comment"></comment>

理解语法

首先,我们有一个模块选择器:

复制代码
<comment></comment>

如果你以前用过 Angular,这个语法看起来应该是很熟悉的。

其次是属性绑定:[comment]。这把我们元素的属性括起来的中括号第一眼看上去似乎有些令人费解。事实上,并不需要它们来帮着把数据传到各个模块中,但没有它们,我们就只能把一个普通的文本字符串传入模块的 @Input()。中括号可以告诉 Angular,这是一个属性绑定以及传给这个变量的值,所以这样就可以把动态数据值插入,传给各模块,而不只是传过去一个字符串了。

最后,我们在“comment”的属性绑定之后有了属性的值。这一块就是告诉 Angular 要注意这个“comment”属性,并且把它传给我们的评论模块。

将概念组合起来

为了像我们在上图中所显示地展示一个评论的列表,我们可以把许多 Angular 概念组合起来,包括 *ngFor。咱们假设我们可以用一个名为 this.comments 的属性的方式把评论数据作为我们模块类的一部分导入。

复制代码
<comment
*ngFor="let comment of comments"
[comment]="comment"></comment>

最终结果看起来像是这样的:

使用评论模块的评论列表

捕获子模块事件

当我们知道了该如何把数据传入评论模块之后,那该怎样把一个模块删掉,并因此从列表中消失呢?这个看起来就有些诡异,因为数据是保存在评论模块的父模块——AppComponent 之中的。

解决这个问题的办法就是调用名为 @Output() 的方法,它可以利用 EventEmitter,让子模块发射出父模块可以捕获的事件。

让子模块可以与父模块通信的第一步就是用 @Output() 描述符给我们的模块加上一个新的类属性。

复制代码
@Component({
selector: 'comment',
templateUrl: './comment.component.html'
})
export class CommentComponent {
@Input() private comment;
@Output() private onDelete = new EventEmitter();
deleteComment() {
this.onDelete.emit(this.comment);
}
}

在这个 CommentComponent 的代码里,我们可以在 delete 按钮被按下时调用 deleteComment() 方法,让我们可以捕获这些从父模块发过来的事件。

复制代码
<button (click)="deleteComment()">Delete</button>

从父模块中捕获事件

在 AppComponent 中,我们需要有个新方法来处理删除评论的行为。这个方法会收到:

复制代码
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
/**[code omitted]**/
onCommentDelete(comment) {
// logic to remove comment from comments array
}
}

在我们的视图中,我们只需要告诉 Angular 当 onDelete 事件被触发时,要调用 onCommentDelete() 方法。

复制代码
<comment
*ngFor="let comment of comments"
[comment]="comment"
(onDelete)="onCommentDelete($event)"></comment>

当我们的删除功能就绪之后我们的程序看起来是这样的:

现在有了 Angular 的 @Output() 描述符,我们就可以删除评论了。

还有另外一种获取数据的方法

到目前为止,我们还只讨论了父 - 子模块之间进行模块通信的方法。尽管现在这种通信方法已经可以满足大多数人的需求,但随着应用程序规模的增长,继续维护父子之模块间的数据通信模式就会越来越困难。对于大型程序来说,用数据库来减轻单个模块的工作量的方法通常都是有效的。数据库可以做为中心存储,在需要时可以被应用程序的各个单独模块调用。单个模块可以直接连上数据库,只使用它们所需要的那一部分数据,而不是把数据手动地顺序按子模块链不断传下去,从而减轻了父模块和子模块所承担的把数据传来传去的责任。

如果你熟悉 React,就会知道这正是 Redux 要解决的问题。可是有了 Angular,我们就有了另一个可用的名为 ngrx 的库,而这恰好是受 Redux 启发而成的。在这两个库之间有些关键不同:类型和观测值。ngrx 库对 TypeScript 生态系统的依赖非常重,所以会比 Redux 更加繁冗,但却让调试和调查问题变得更容易。

在用 ngrx 时,我们的状态是一个单独不变的数据结构。为了让我们的状态可变,我们可以用行为的方式来调用函数。反之,这些行为可以告诉我们的由单纯的函数组成的处理逻辑,哪一块的状态是可变的。这样,我们的应用程序就可以有状态的新版本数据了,而那些关注这些数据的模块就可以马上收到新数据。当这些模块收到新数据之后,它们会被自动重新展示,让我们的视图始终与数据库中的数据保持一致。

这对于开发又意味着什么?

这从概念上表明,是有可能从系统外部把数据直接传给某个模块,而不必通过父子关系的,这在事实上对于开发来说意味着什么呢?

如果我们想在两个不同的地方显示评论的条数呢?仅仅依靠模块的层级架构是很难实现的,这种情况下使用 ngrx 的中心存储就很有效了。

在较大的程序内部,把数据直接传给某个模块可以解决很多问题。随着各个模块要处理越来越多的任务,再要增加类似跟踪把数据传入子模块这类额外的任务就会变得复杂。当不能把传输数据的负担交给外部数据库时,维护大型 Angular 程序时保持头脑清醒就很必要了。

在上面的例子里,一个外部数据库(图中没有画出来)可以用来把信息传给 SidebarComponent,表示有多少评论可用,“有两条评论”,同时还把真实的评论内容发给 CommentList 模块。这些数据完全绕过了父模块 AppComponent。

快速回顾一下 Angular 的模块通信机制

读过上文,我们已经对 Angular 的模块之间如何通信有了一些了解。我们知道了怎样把数据从一个父模块传入一个子模块,而且我们也知道了怎么使用 Angular 的 @Input() 描述符。

我们也知道了怎样使用 @Output() 描述符,以及如何使用 EventEmitter 来把数据从一个子模块发回给一个父模块。

除此之外,当应用程序规模增长之后,我们也知道了如何用 ngrx 来减轻父子关系的压力。通过使用一个单独的数据库,我们就可以让各个模块自己获取数据,而不必通过多层子模块居中传递来把数据传到真正的目的地去。这就让维护大规模应用程序变得容易了。这些原理也适用于 React 之类的库,他们也用非常类似的办法解决了相同的问题。

你可以在这个链接上看到我们的演示程序视频,相应的代码也可以在这里下载。

如何进一步学习

如果你有兴趣对Angular 了解得更多些,请一定看看Code School 的“ Accelerating through Angular 2 ”课程,再看看 Gregg Pollack 和我自己的“ build an Angular 2 app with component interaction & routing ”课程(仅供 Code School 会员学习)。

另外,可以再看看 Angular 关于模块交互的文档,进一步了解底层机制,以及随着框架的快速演进,最新的语法和最佳实践。

最后,你也可以再读读 ngrx 官方网站上的 ngrx 文档,或者在这里看看我用ngrx 构建的一个示例程序。

关于作者

Sergio Cruz是 Code School 的一位应用程序开发者和咨询师,兴趣广泛,尤其是 JavaScript。最近,他新讲授了一些 Code School 的 React 课程,“ Powering up With React ”。当他不在 Code School 敲代码时,他也会去 ng-conf 或 OSCON 等 JavaScript 相关的会议上作作讲座。

阅读英文原文 Getting Components to Communicate in Angular

2017-03-15 18:466455
用户头像

发布了 152 篇内容, 共 68.1 次阅读, 收获喜欢 63 次。

关注

评论

发布
暂无评论
发现更多内容

抖音春晚活动背后的 Service Mesh 流量治理技术

火山引擎开发者社区

微服务 后端 后端技术

OneFlow学习笔记:从Python到C++调用过程分析

OneFlow

c++ Python Relu 调用过程分析

Kubernetes家族容器小管家Pod在线答疑?

囧么肥事

Kubernetes 云原生 k8s #Kubernetes# 容器服务

库存管理与资产管理的区别是什么?

低代码小观

低代码 企业管理 资产管理 资产安全 WMS仓库管理

重新组装电脑后需要注意些什么?

InfoQ IT百科

云小课|教你如何使用RDS for PostgreSQL插件

华为云开发者联盟

postgresql 插件 开源数据库 RDS for PostgreSQL

FL Studio20.8最新中文破解版下载

茶色酒

存储器管理有哪几种方式?

InfoQ IT百科

破浪人丨国内首位 Envoy Maintainer!王佰平独家讲述四年开源之路

网易数帆

开源 云原生 Service Mesh 服务网格 envoy

通过 SingleFlight 模式学习 Go 并发编程

万俊峰Kevin

微服务 并发编程 web开发 go-zero Go 语言

所以,我们依然要读书!

博文视点Broadview

不用加盟费也能加盟自助洗车吗?

共享电单车厂家

自助洗车加盟 自助洗车加盟费 车白兔自助洗车 加盟自助洗车多少钱

实时系统的类型及特征?

InfoQ IT百科

纯 JS 实现 WebRTC 视频通话

杨成功

音视频 WebRTC

虚拟存储器有哪些特征?

InfoQ IT百科

分页存储和分段存储有什么区别?

InfoQ IT百科

想代理加盟自助洗车要怎么做?

共享电单车厂家

自助洗车机价格 自助洗车加盟 车白兔自助洗车机 自助洗车代理

Camtasia2022mac破解版电脑录屏软件

茶色酒

Camtasia2022

无处不在的TDD思维

Bruce Talk

敏捷 TDD Agile

电脑内存越大处理速度就越快吗?

InfoQ IT百科

CorelDRAW2022无限使用安装下载

茶色酒

cdr2022

I/O设备的四种控制方式是什么?

InfoQ IT百科

【生活常识】塑料分级

Sher10ck

焱融 YRCloudFile 跨云多源数据管理,直击自动驾驶 “割裂式存储”痛点

焱融科技

自动驾驶 云计算 分布式 高性能 文件存储

Windows操作系统升级后会出现与CPU不兼容情况吗?

InfoQ IT百科

自助洗车机利润怎么样?加盟靠谱否

共享电单车厂家

自助洗车加盟 自助洗车机利润 车白兔自助洗车

24小时自助洗车机价格一般多少

共享电单车厂家

自助洗车机价格 自助洗车加盟 自助洗车设备多少钱 车白兔自助洗车机

自动洗车加盟选择哪家比较好?

共享电单车厂家

自助洗车机价格 自助洗车加盟 自助洗车机厂家 车白兔自助洗车

Camtasia2022汉化版本屏幕录像软件

茶色酒

Camtasia2022

面试突击42:synchronized和ReentrantLock有什么区别?

王磊

Java java面试

主板的稳定性和哪些因素有关系?

InfoQ IT百科

Angular的模块间通信_JavaScript_Sergio Cruz_InfoQ精选文章