参考地址1
参考地址2
先上一张组件间通讯的分类情况图。
下面分步骤说明以上几种分类如何实现。
一、组件间是父子组件关系
1、父子组件间进行了数据绑定
(1)、用@Input
和@Output
装饰器
在子组件cc1
中通过@Input
装饰器声明属性list
是一个输入属性,通过@Output
装饰器声明属性addItem
是一个输出属性:
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-cc1',
template: `
{{item}}
`
})
export class Cc1Component implements OnInit {
@Input() list: Array;
@Output() addItem: EventEmitter = new EventEmitter();
constructor() { }
ngOnInit() {
}
onClick() {
const num = Math.round(Math.random() * 100);
this.addItem.emit(num);
}
}
在父组件cp
中引入了子组件cc1
:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-cp',
template: `
`
})
export class CpComponent implements OnInit {
testData: Array = [1, 2, 3];
constructor() { }
ngOnInit() {
}
doAdd(item: number) {
this.testData = [...this.testData, item];
}
}
这样,在子组件操作数据,父组件就可以接收到变化。
(2)、用onChanges
生命周期监听输入属性的变化
在子组件cc2
中通过@Input
装饰器声明属性list
是一个输入属性,通过onChanges
生命周期监听输入属性的变化:
import { Component, OnInit, OnChanges, Input, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-cc2',
template: `
{{item}}
合计为:{{count}}
`
})
export class Cc2Component implements OnInit, OnChanges {
@Input() list: Array;
count: number = 0;
constructor() { }
ngOnInit() {
this.sum();
}
sum() {
this.count = this.list.reduce((prev, cur, index, array) => {
return prev + cur;
});
}
ngOnChanges(changes: SimpleChanges): void {
this.sum();
}
}
在父组件cp
中引入了子组件cc2
:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-cp',
template: `
`
})
export class CpComponent implements OnInit {
testData: Array = [1, 2, 3];
constructor() { }
ngOnInit() {
}
doClick() {
const num = Math.round(Math.random() * 100);
this.testData = [...this.testData, num];
}
}
这样,当父组件中绑定的数据变化时,子组件就能监听到。
2、父子组件间没有进行数据绑定
(1)、将子组件作为本地变量
子组件cc3
中的代码如下:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-cc3',
template: `
{{item}}
`
})
export class Cc3Component implements OnInit {
list: Array = [];
constructor() { }
ngOnInit() {
}
addItem() {
const num = Math.round(Math.random() * 100);
this.list = [...this.list, num];
}
}
在父组件cp
中引入了子组件cc3
,并新建一个本地变量mySon
来代表此子组件,这样就可以在父组件中调用子组件的属性和函数了:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-cp',
template: `
`
})
export class CpComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
注意:在这种情况下,只能在父组件的模板中调用子组件的属性和函数。
(2)、用@ViewChild
装饰器
还是之前的子组件cc3
的代码不变:
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-cc3',
template: `
{{item}}
`
})
export class Cc3Component implements OnInit {
list: Array = [];
constructor() { }
ngOnInit() {
}
addItem() {
const num = Math.round(Math.random() * 100);
this.list = [...this.list, num];
}
}
在父组件cp
中依旧引入了子组件cc3
,然后用@ViewChild
装饰器定义变量mySon
来代表此子组件cc3
,这样就可以在父组件中调用子组件的属性和函数了:
import { Component, OnInit, ViewChild } from '@angular/core';
import { Cc3Component } from '../cc3/cc3.component';
@Component({
selector: 'app-cp',
template: `
`
})
export class CpComponent implements OnInit {
@ViewChild(Cc3Component, {static: false}) mySon: Cc3Component;
constructor() { }
ngOnInit() {
}
doClick() {
this.mySon.addItem();
}
}
注意:在这种情况下,只能在父组件的控制器中调用子组件的属性和函数。
总结一下:如果父子组件没有进行数据绑定,又要进行通讯,那么耦合度就高了,父组件中不可避免地要出现子组件的属性或方法,无论是在父组件的模板中还是控制器中。
二、组件间是非父子组件关系
如果组件间是非父子组件关系,那么使用服务进行组件间的通讯是个不错的选择。
新建一个服务SService
,代码如下:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class SService {
myData: Array = [];
myDataSource = new Subject();
constructor() { }
addInfo(info: any) {
this.myData = [...this.myData, info];
this.myDataSource.next(this.myData);
}
}
新建组件ca
,注入SService
服务,代码如下:
import { Component, OnInit } from '@angular/core';
import { SService } from '../server/s.service';
@Component({
selector: 'app-ca',
template: `
我是a组件
`
})
export class CaComponent implements OnInit {
constructor(private server: SService) { }
ngOnInit() {
}
onClick() {
const num = Math.round(Math.random() * 100);
this.server.addInfo(num);
}
}
新建组件cb
,注入SService
服务,代码如下:
import { Component, OnInit } from '@angular/core';
import { SService } from '../server/s.service';
@Component({
selector: 'app-cb',
template: `
我是b组件
{{item}}
`
})
export class CbComponent implements OnInit {
list = [];
constructor(private server: SService) { }
ngOnInit() {
this.server.myDataSource.subscribe(r => {
this.list = r;
});
}
}
之后,在app
组件中引入组件ca
和组件cb
:
这样,两个没有关联关系的组件就可以通讯了。