父子组件通信
#
在真实的应用中,组件最终会构成树形结构,就像人类社会中的家族树一样:
在树形结构里面,组件之间有几种典型的关系:父子关系、兄弟关系、没有直接关系。
相应地,组件之间有以下几种典型的通讯方案:
-
直接的父子关系:父组件直接访问子组件的 public 属性和方法。
-
直接的父子关系:借助于 @Input 和 @Output 进行通讯
-
没有直接关系:借助于 Service 单例进行通讯。
-
利用 cookie 和 localstorage 进行通讯。
-
利用 session 进行通讯。
父子通信:Input Down#
参考文档:https://angular.io/guide/component-interaction#pass-data-from-parent-to-child-with-input-binding
-
父组件通过子组件标签传递属性
-
子组件在内部声明
@Input
接收
-
Input 是单向的
-
父组件如果把数据改了,子组件也会更新
-
但是反之不会
-
有一个例外,引用类型修改
-
下面是一个示例:
子组件:
import { Component, Input } from '@angular/core'; import { Hero } from './hero'; @Component({ selector: 'app-hero-child', template: ` <h3>{{hero.name}} says:</h3> <p>I, {{hero.name}}, am at your service, {{masterName}}.</p> ` }) export class HeroChildComponent { // 声明接收父组件传递的数据 @Input() hero: Hero; @Input('master') masterName: string; // 接收 master 重命名为 masterName }
父组件:
import { Component } from '@angular/core'; import { HEROES } from './hero'; @Component({ selector: 'app-hero-parent', template: ` <h2>{{master}} controls {{heroes.length}} heroes</h2> <!-- 在子组件标签上传递数据 --> <app-hero-child *ngFor="let hero of heroes" [hero]="hero" [master]="master"> </app-hero-child> ` }) export class HeroParentComponent { heroes = HEROES; master = 'Master'; }
父子通信:Output Up#
参考文档:https://angular.io/guide/component-interaction#parent-listens-for-child-event
@Output
的本质是事件机制,我们可以利用它来订阅子组件上发布的事件,子组件上这样写:
import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ selector: 'app-voter', template: ` <h4>{{name}}</h4> <button (click)="vote(true)" [disabled]="voted">Agree</button> <button (click)="vote(false)" [disabled]="voted">Disagree</button> ` }) export class VoterComponent { @Input() name: string; @Output() onVoted = new EventEmitter<boolean>(); voted = false; vote(agreed: boolean) { this.onVoted.emit(agreed); // 传递的数据就是事件对象 this.voted = true; } }
在父组件中订阅处理:
import { Component } from '@angular/core'; @Component({ selector: 'app-vote-taker', template: ` <h2>Should mankind colonize the Universe?</h2> <h3>Agree: {{agreed}}, Disagree: {{disagreed}}</h3> <app-voter *ngFor="let voter of voters" [name]="voter" (onVoted)="onVoted($event)"> </app-voter> <!-- $event在这里是自定义事件对象,接收到的是子组件内部发布事件传递的数据 --> ` }) export class VoteTakerComponent { agreed = 0; disagreed = 0; voters = ['Mr. IQ', 'Ms. Universe', 'Bombasto']; onVoted(agreed: boolean) { agreed ? this.agreed++ : this.disagreed++; } }
#
参考文档:https://angular.io/guide/component-interaction#parent-interacts-with-child-via-local-variable
<app-foo #child></app-foo> <button (click)="child.increment()">调用子组件的方法</button>
显然,子组件里面必须暴露一个 public 型的 childFn 方法,就像这样:
export class FooComponent implements OnInit { public message: string = 'foo message' public count: number = 0 constructor() { } public increment (): void { this.count++ } ngOnInit() { } }
以上是通过在模板里面定义局部变量的方式来直接调用子组件里面的 public 型方法。在父组件的内部也可以访问到子组件的实例,需要利用到 @ViewChild 装饰器,示例如下:
@ViewChild(ChildComponent) private childComponent: ChildComponent;
关于 @ViewChild 在后面的内容里面会有更详细的解释。
没有直接关系通信:Service 单例#
参考文档:https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service
#
#
小结#
组件间的通讯方案是通用的,无论你使用什么样的前端框架,都会面临这个问题,而解决的方案无外乎本文所列出的几种。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2020-03-19 数据库读写分离之配置Django实现数据库读写分离