angular组件之间通信的机制
1 输入性属性: 通常带着@Input装饰器
2 通过setter截听属性值的变化。使用一个输入属性的setter, 以拦截父组建中值的变化,并采取行动;
eg: export ChildComponent {
private _name = '';
@Input() set name( name: string) { this._name = (name && name.trim()) || '< no name set >'
get name() : string { return this._name};
}
@Component ({
template: `
<h2>Master controls {{names.length}} names</h2>
<app-name-child *ngFor="let name of names" [name]="name"></app-name-child>`
})
3 ngOnChanges() 来截听输入属性值的变化。
父组件监听子组件的事件。
子组件暴露一个EventEmitter属性,当事件发生时,子组件利用该属性emits(向上弹射)事件。通常带有@Output装饰器,
import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'app-voter',
template: `
<h4>{{name}}</h4>
<button (click)="vote(true)" [disabled]="didVote">Agree</button>
<button (click)="vote(false)" [disabled]="didVote">Disagree</button>
`
})
export class VoterComponent {
@Input() name: string;
@Output() voted = new EventEmitter<boolean>();
didVote = false;
vote(agreed: boolean) {
this.voted.emit(agreed);
this.didVote = 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"
(voted)="onVoted($event)">
</app-voter>
`
})
export class VoteTakerComponent {
agreed = 0;
disagreed = 0;
voters = ['Narco', 'Celeritas', 'Bombasto'];
onVoted(agreed: boolean) {
agreed ? this.agreed++ : this.disagreed++;
}
}
父组件与子组件通过本地变量互动, 父组件不能使用数据绑定来读取子组件的属性。 把本地变量(#var) 放到子组件的tag中,用来代表子组件。
这样父组件的模板就得到了子组件的引用,于是可以在父组件的模板中访问
父组件调用@viewChild() 。这个本地变量方法是简单便利的方法,但是父组件-子组件的连接必须全部在父组件的模板中进行,父组件本身的代码对子组件没有访问权限。
如果父组件的类需要读取子组件的属性或调用子组件的方法,就不能使用本地变量方法。当父组件类需要这种访问时,可以把子组件作为ViewChild, 注入到父组件中。
import { AfterViewInit, ViewChild } from '@angular/core';
import { Component } from '@angular/core';
import { CountdownTimerComponent } from './countdown-timer.component';
@Component({
selector: 'app-countdown-parent-vc',
template: `
<h3>Countdown to Liftoff (via ViewChild)</h3>
<button (click)="start()">Start</button>
<button (click)="stop()">Stop</button>
<div class="seconds">{{ seconds() }}</div>
<app-countdown-timer></app-countdown-timer>
`,
styleUrls: ['../assets/demo.css']
})
export class CountdownViewChildParentComponent implements AfterViewInit {
@ViewChild(CountdownTimerComponent, {static: false})
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(); }
}
父组件和子组件通过服务来通讯。
父组件和子组件共享同一个服务,利用该服务在组件家族内部实现双向通讯。 该服务的作用域被限制在父组件和其子组件之内,这个组件子树之外的组件将无法访问该服务或与他们通信。
eg:
import { Injectable } from '@angular/coore';
import { Subject} from 'rxjs'; // Subject(主体) 相当于EventEmitter,并且是将值或事件多路推送给多个Observer的唯一方式。
@Injectable()
export class MissionService {
// Observable string source
private mission AnnouncedSource = new Subject<string>();
private missionConfirmedSource = new Subject<string>();
//Observable string streams
missionAnnouced$ = this.missionAnnouncedSource;asObservable();
missionConfirmed$ = this.missionCOnfirmedSource.asObservable();
// Service message commands
announceMission(mission: String) { this.missionAnnounceSource.next(mission);}
confirmMission(astronaur: String) {this.missionConfirmedSource.next(astronaur);}
}
其中子组件: missionService.missionAnnoiced$.subscribe(res => {})