通过输入型绑定把数据从父组件传到子组件
Angular对于父组件 => 子组件的数据通信做法和Vue很相似。
// 父组件html模板 <app-hero-child *ngFor="let hero of heroes" [hero]="hero" [master]="master"> </app-hero-child> // 子组件接收数据 import { Component,Input } from '@angular/core'; import { Hero } from './hero'; export class HeroChildComponent { @Input() hero: Hero; @Input('master') masterName: string; } // 第二个@Input为子组件的属性名masterName指定一个别名master,但是这个做法并不推荐
看着是不是很眼熟,写代码的逻辑和Vue几乎可以说是一样了,只是写法上略有区别而已。
这个问题下还有两个截听输入属性值变化的方法,代码逻辑不难推,但是其中的应用场景方面我还没想到是怎么样的,之后也许继续看Angular文档会理解的更透彻一些,届时再来补充啦~~
父组件监听子组件的事件
这个操作方法也和Vue中的做法非常接近,而且在上一篇笔记中也有所提及。
具体思路:子组件暴露一个EventEmitter属性,当事件发生时,子组件利用该属性emits(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。
还有,子组件的EventEmitter属性是一个输出属性,通常带有@Output装饰器,比较完整的示例如下:
// 子组件:先在自己的组件中触发了vote方法,然后在vote方法中向父组件发出onVoted事件,同时传送一个payload(agreed) // 在Vue中的写法是this.$emit(onVoted,agreed) import { Component,EventEmitter,Input,Output } from '@angular/core'; export class VoterComponent { @Input() name: string; @Output() onVoted = new EventEmitter<boolean>(); voted = false; vote(agreed: boolean) { this.onVoted.emit(agreed); this.voted = true; } } // 父组件:监听onVoted事件,如果监听到了则触发自己组件中的agree方法,同时通过$event把payload传参给agree html: <app-voter (onVoted)="onVoted($event)"></app-voter> ts: export class VoteTakerComponent { onVoted(agreed: boolean) { agreed ? this.agreed++ : this.disagreed++; } }
父子组件的其他互动关系
父组件与子组件通过本地变量互动
父组件对子组件的数据绑定属于单向绑定,子组件无法直接把数据、属性和自身的方法传送给父组件使用。尽管有EventEmitter属性,但是有时候需要直接访问子组件的内容,用这种方法并不合适。
// 可以在父组件的模板中直接访问子组件的所有属性和方法,例如此例便是直接访问了子组件的start(),stop()方法和seconds属性 <button (click)="timer.start()">Start</button> <button (click)="timer.stop()">Stop</button> <div class="seconds">{{timer.seconds}}</div> <app-countdown-timer #timer></app-countdown-timer>
父组件调用@ViewChild()
上述方法有一定局限性:父组件-子组件的连接必须全部在父组件的模板中进行。父组件本身的代码对子组件没有访问权。如果想要在代码中直接访问子组件的内容,可以使用这个方法把子组件作为ViewChild,注入到父组件里面,具体操作如下:
// 需要通过@ViewChild属性装饰器,将子组件CountdownTimerComponent注入到私有属性timerComponent里面,并挂在AfterViewInit生命周期钩子里 export class CountdownViewChildParentComponent implements AfterViewInit { // 在父组件中将子组件注册为变量timerComponent,记得在括号里写明子组件名字~~ @ViewChild(CountdownTimerComponent) private timerComponent: CountdownTimerComponent; // 这样就可以通过this.timerComponent访问子组件的内容了 start() { this.timerComponent.start(); } stop() { this.timerComponent.stop(); } }
通过服务来通讯
父组件和它的子组件(们)共享同一个服务,利用该服务在父子组件之间实现双向通讯。
该服务实例的作用域被限制在父组件和其子组件(们)内。这个组件子树之外的组件将无法访问该服务或者与它们通讯。
父子组件通过各自的构造函数注入该服务。文档中的例子还需要一些额外知识才能明白,之后再分析啦!~
前端新人,写的不对的地方还请指出;如果觉得对你有帮助,可以点个赞鼓励一下我哦!~~