Angular中组件间的通信

组件表示了Angular中的构建块,在Angular应用中每一个可视化元素都是由组件构成的。基于组件架构的好处是它更像JavaScript的function函数一样,如果某一个代码段变得越来越复杂或者需要处理的业务越来越多,你可以把它进行拆分,使每个代码段只完成一项任务。

当我们把一个组件拆分成多个更小的组件的时候,需要保证他们之间可以进行数据传递,以确保在我们的应用中所有的数据都是同步的,这就意味着正确的组件之间的通讯变得十分必要。幸运的是Angular为我们提供了这样的工具。
这里写图片描述

传值给组件

在Angular中,当父组件需要传值给子组件时,我们使用@Input来进行标识。假设我们构建了一个应用,在其中的一个页面上我们需要展示评论列表。AppComponent负责加载评论数据的数组,我们将把每个评论数据发送给评论组件。
我们将允许使用@Input()把评论数据传递给子组件,以下是评论组件的代码:

@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查看this.comment属性并传递给我们的评论组件。

组合概念

为了实现像上图中我们看到的评论列表,我们要组合一些Angular的概念,包括*ngFor。假设我们能够把评论数据加载到我们组件类的this.comments属性中。

<comment
  *ngFor="let comment of comments"
  [comment]="comment"></comment>

最后的结果看起来像这样的:
这里写图片描述

捕获子组件事件

现在我们了解了如何把数据传递给评论组件,那么怎么删除一个组件并把它从列表中移除呢?这是一个非常棘手的问题,因为数据是在父组件当中。
解决这个问题的一种方式是使用@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模板中,当我们点击删除按钮时,调用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>

这是我们的应用看起来像我们执行了删除功能的样子
这里写图片描述

另一种获取数据的方式

到目前为止,我们仅仅涉及了组件通讯中父/子层级组件的通讯问题。这些可能适用于我们大部分的需求,当随着应用的不断壮大,很难再去维护这种在父子层级上的数据传递,所以对于一个更大的应用来说,使用“数据存储”来减少单个组件的工作负载是比较合理的。数据存储以作为单个组件的中心仓库方式进行工作,当应用程序的某一部分需要组件时,他们被进行调用。为了替代手动地向下传递数据到子链,单个组件能够在数据存储中订阅他们需要的数据,减少父子组件之间传递数据的负担。

如果你熟悉React,这个问题是由Redux所解决的。但是在Angular中,我们也有一个可选择的库,叫做ngrx,它的灵感来自于Redux。在这两个库之间有细微的关键区别:types and observables。ngrx库十分依赖于TypeScript的生态系统,它比Redux需要更多的样板文件,不过这也使跟踪调试变得更加容易。

当使用ngrx时,我们的状态是一个单一不可变的数据结构。为了改变我们的状态,我们通过调用动作函数来进行。反过来,那些动作告诉我们的reducers(它们是由一些单纯的函数所组成的),哪些部分的状态能够被改变。因此,我们的应用现在将有下一个版本的状态并且所有订阅它的组件将马上收到新的数据。当组件收到新的数据时,它们也会进行自动的渲染,使我们渲染的视图与我们存储中的数据总是保持一致。

对于开发来说这意味着什么呢?
从概念上来说的意义是能够把数据从外部数据源中直接传递给组件,而不用通过父子组件关系的形式,那么对于开发来说实际意义又是什么呢?
这里写图片描述

把数据直接传递给组件对于大型应用来说是十分有意义的,因为组件需要处理更多的任务,添加额外的任务,如一直跟踪发送数据给子组件,会变得复杂。不过把传递数据的负担转移到外部数据存储并不是必要的,以适合自身的方式来维护你的大型Angular应用才是很有意义的!

在上面的示例中,外部存储(非图示)将有多少评论可用的信息,“2个评论可用传递给SidebarComponent以及将实际的评论传递给CommentList组件,这次的数据传递完全的绕过了父AppComponent。

原文:https://www.infoq.com/articles/angular-component-communication

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值