文章目录
一、数据通信
1.父组件向子组件传递
a.通过输入型属性绑定把数据从父组件传到子组件
在子组件中定义变量:
@Input() childVariable = "";
在子组件模板中输出该变量:
<p>{
{childVariable}}</p>
在父组件中定义变量:
parentVariable = ""
在父组件模板中输入该变量值:
<p>父组件</p>
<app-person [childVariable]="parentVariable"></app-person>
<input type="text" [(ngModel)]="parentVariable">
这种方式,在子组件中定义了输入型属性(@Input),并通过该属性,在父组件中给子组件传递数据。
b.通过 setter 截听输入属性值的变化
与输入型属性绑定方式类似,在子组件中定义输入型的getter setter方法(@Input),并通在父组件中调用该属性的getter setter方法,达到了向子组件传递数据的目的。
在子组件中定义变量:
_childName = "";
@Input()
get childName() : string {
return this._childName
}
set childName(name : string) {
this._childName = name
}
在子组件模板中输出该变量:
<p>{
{childName}}</p>
在父组件中定义变量:
myChildName = ""
<p>父组件</p>
<app-person [childName] = "myChildName"></app-person>
<input type="text" [(ngModel)] = "myChildName">
这种方式,通过在父组件中设置子组件的属性,调用了子组件改属性的getter setter方法,从而通过getter setter方法,实现了在父组件中给子组件传递数据。
夜半子时,今天先写到这~
2021.11.10 继续ing
2.父组件监听子组件事件
原理:子组件暴露一个 EventEmitter 属性,当事件发生时,子组件利用该属性 emits(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。
子组件的 EventEmitter 属性是一个输出属性,通常带有@Output 装饰器:
@Input() name = ""
@Output() voted = new EventEmitter<boolean>();
didVote = false;
vote(agreed : boolean) {
this.voted.emit(agreed);
this.didVote = true;
}
在子组件模板中:
<h4>{
{name}}</h4>
<button (click)="vote(true)" [disabled]="didVote">Agree</button>
<button (click)="vote(false)" [disabled]="didVote">Disagree</button>
父组件:
agreed = 0;
disagreed = 0;
voters = ['test1', 'test2', 'test3'];
onVoted(agree : boolean) {
agree ? this.agreed ++ : this.disagreed ++;
}
父组件模板:
<h2>Should mankind colonize the Universe?</h2>
<h3>Agree: {
{agreed}}, Disagree: {
{disagreed}}</h3>
<app-emittertest *ngFor="let voter of voters" [name] = "voter" (voted) = "onVoted($event)"></app-emittertest>
3.父组件与子组件通过变量互动
a.本地变量
父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法,如下例所示。
子组件:
intervalId = 0;
message = "";
seconds = 0;
start() {
this.startTiming();
}
suspend() {
this.clearTimer();
this.message = this.seconds + "Holding...."
}
stop() {
this.clearTimer();
this.seconds = 0;
this.message = "Stop."
}
子组件模板:
<p>{
{message}}</p>
父组件模板:
<app-timertest #timer></app-timertest>
<button (click)="timer.start()">start</button>
<button (click)="timer.stop()">stop</button>
<button (click)="timer.suspend()">suspend</button>
b.@ViewChild
本地变量方法有一定局限性,因为父组件与子组件的连接必须全部在父组件的模板(HTML)中进行。父组件本身的代码(ts)对子组件没有访问权。
当父组件类需要这种访问时,可以把子组件作为 ViewChild,注入到父组件里面。
子组件:
intervalId = 0;
message = "";
seconds = 0;
start() {
this.startTiming();
}
suspend() {
this.clearTimer();
this.message = this.seconds + "Holding...."
}
stop() {
this.clearTimer();
this.seconds = 0;
this.message = "Stop."
}
子组件模板
<p>{
{message}}</p>
父组件:
@ViewChild(TimerviewchildtestComponent)
private timertester !: TimerviewchildtestComponent;
start() {
this.timertester.start();
}
stop() {
this.timertester.stop();
}
suspend() {
this.timertester.suspend();
}
父组件模板:
<app-timerviewchildtest></app-timerviewchildtest>
<button (click)="start()">start</button>
<button (click)="stop()">stop</button>
<button (click)="suspend()">suspend</button>
4.父组件和子组件通过服务来通讯
父组件和它的子组件共享同一个服务,利用该服务在组件家族内部实现双向通讯。
该服务实例的作用域被限制在父组件和其子组件内。这个组件子树之外的组件将无法访问该服务或者与它们通讯。
子组件:
message = "";
constructor(private commonService : CommonService) {
}
toParent() {
this.commonService.variable2 = "Hello, this is a message from child."
}
getMessage() {
this.message = this.commonService.variable1;
}
子组件模板:
<p>子组件</p><br>
<p>{
{message}}</p><button (click)="getMessage()">获取消息</button><br>
<button (click)="toParent()">子 to 父</button><br>
父组件:
message = "";
constructor(private commonService : CommonService) {
}
toChild() {
this.commonService.variable1 = "Hello, this is a message from parent."
}
getMessage() {
this.message = this.commonService.variable2;
}
父组件模板:
<p>{
{message}}</p><button (click)="getMessage()">获取消息</button><br>
<button (click)="toChild()">父 to 子</button><br>
<app-twowaycommunicationtest></app-twowaycommunicationtest>
service服务:
@Injectable({
providedIn: 'root'
})
export class CommonService {
constructor() {
}
variable1 = "";
variable2 = "";
}