子:
@Input() hero!: Hero;
@Input('master') masterName = ''; //不推荐起别名
父:
//html:
<app-hero-child [hero]="hero" [master]="master"> </app-hero-child>
//ts:
export class HeroParentComponent {
hero = '';
master = 'Master';
}
使用一个输入属性的 setter,以拦截父组件中值的变化,并采取行动。
e.g. 子组件 NameChildComponent 的输入属性 name 上的这个 setter,会 trim 掉名字里的空格,并把空值替换成默认字符串。
子:
export class NameChildComponent {
@Input()
get name(): string { return this._name; }
set name(name: string) {
this._name = (name && name.trim()) || '' ;
}
private _name = '';
}
父:
//html
<app-name-child *ngFor="let name of names" [name]="name"></app-name-child>
//ts
export class NameParentComponent {
// Displays 'Dr. IQ', '', 'Bombasto'
names = ['Dr. IQ', ' ', ' Bombasto '];
}
使用 OnChanges 生命周期钩子接口的 ngOnChanges() 方法来监测输入属性值的变化并做出回应。
当需要监视多个、交互式输入属性的时候,本方法比用属性的 setter 更合适。
子组件暴露一个 EventEmitter 属性,当事件发生时,子组件利用该属性 emits(向上弹射)事件。
父组件绑定到这个事件属性,并在事件发生时作出回应。
【 子组件的 EventEmitter 属性是一个输出属性,通常带有**@Output** 装饰器 】
本框架把事件参数(用 $event 表示)传给事件处理方法
子:
//html
<button type="button" (click)="vote(true)">Agree</button>
//ts
@Output() voted = new EventEmitter<boolean>();
vote(agreed: boolean) {
this.voted.emit(agreed);
}
父:
//html
<app-voter [name]="voter" (voted)="onVoted($event)"></app-voter>
//ts
onVoted(agreed: boolean) { //Todo }
父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法。
子:
//ts
start() { this.countDown(); }
stop() {this.clearTimer(); }
父:
//html
<button type="button" (click)="timer.start()">Start</button>
<button type="button" (click)="timer.stop()">Stop</button>
<div class="seconds">{{timer.seconds}}</div>
<app-countdown-timer #timer></app-countdown-timer>
Q:父组件不能通过数据绑定使用子组件的 start 和 stop 方法,也不能访问子组件的 seconds 属性。
A:把本地变量(#timer)放到()标签中,用来代表子组件。
这样父组件的模板就得到了子组件的引用,于是可以在父组件的模板中访问子组件的所有属性和方法。
这个本地变量方法是个简单明了的方法。
局限性:父组件本身的代码对子组件没有访问权【父组件-子组件的连接全部在父组件的模板中进行】
=> 如果父组件的类需要依赖于子组件类,就不能使用本地变量方法。
父:
//html
<button type="button" (click)="start()">Start</button>
<button type="button" (click)="stop()">Stop</button>
<div class="seconds">{{ seconds() }}</div>
<app-countdown-timer></app-countdown-timer>
//ts
export class CountdownViewChildParentComponent implements AfterViewInit {
@ViewChild(CountdownTimerComponent)
private timerComponent!: CountdownTimerComponent; //子组件
seconds() { return 0; }
ngAfterViewInit() {
// Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ...
// but wait a tick first to avoid one-time devMode
// unidirectional-data-flow-violation error
setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
}
start() { this.timerComponent.start(); }
stop() { this.timerComponent.stop(); }
}
ngAfterViewInit() 生命周期钩子是非常重要的一步。
被注入的计时器组件只有在 Angular 显示了父组件视图之后才能访问,所以它先把秒数显示为 0。
父组件和它的子组件共享同一个服务,利用该服务在组件家族内部实现双向通讯