组件交互
父组件传值给子组件
在父子组件的应用当中,组件通讯是非常重要的一环.现有两个组件,现在我们尝试将父类的输入框值传给子类的输入框值.在输入内容之后点击按钮即可完成.接下来我们分析下这个流程:
- 父组件取得值并将值与数据源中的 fatherValue1进行双向绑定
- 点击按钮后触发数据源事件,将 fatherValue1的值赋值给 childValue1
- 在 child-communication 标签上存在从数据源到视图的单向绑定,Angular变更检查发现 childValue1 的值不一样了(初值为空),将 childValue1的值流入子组件,子组件利用 ngModel 对 childValue1进行了双向绑定,因此修改了子组件的输入框值.
父组件html+ts
<h1>我是父组件</h1>
<input nz-input class="input" [(ngModel)]="fatherValue1" placeholder="父组件的输入框">
<button (click)="transferData()" nz-button nzType="primary">传值给子组件</button>
<child-communication [childValue1]="childValue1"></child-communication>
fatherValue1;
childValue1;
transferData() {
this.childValue1 = this.fatherValue1;
}
子组件html+ts
<h1>我是子组件</h1>
<input nz-input class="input" [(ngModel)]="childValue1" name="childValue1" placeholder="子组件的输入框">
@Input() childValue1: string;
这里思考一个问题,如果在第一次传值之后,修改子组件的值再按传值按钮,会发现父组件并不能修改子组件的值,请思考一下这是为什么?
这是因为当第一次传值时, 父组件 childValue1与 fatherValue1是一致的,在子组件修改内容之后,虽然修改了子组件内部的 childValue1 ,但是父组件的 childValue1与 fatherValue1还是一样的.也就导致Angular的变更检查结果为未发生变化,也就导致父组件未能将值流入子组件.
既然未变更值他就无法将数据流入子组件,那么我们只要在数据源事件中,每次都重置下 childValue1再赋值,不就发生了数据变更吗?即可达到每次点击都变更的效果.
类调用
@ViewChild(ChildCommunicationComponent) private childComponent: ChildCommunicationComponent;
在父组件的数据源中,对子组件的引用使用的是 类调用,即参数都是子组件的类名.所以子组件有个输入框,点击子组件的按钮可以正常弹出值.但是点击父类,也能弹出信息,但是却无值
实例调用
@ViewChild('child') private childComponent2: ChildCommunicationComponent;
父组件html+ts
<h1>我是父组件</h1>
<button (click)="callChildFunction3()" nz-button nzType="primary">调用子组件方法</button>
<child-communication #child></child-communication>
@ViewChild('child') private childComponent2: ChildCommunicationComponent;
callChildFunction3() {
this.childComponent2.childFunction3();
}
子组件html+ts
<h1>我是子组件</h1>
<input nz-input class="input" [(ngModel)]="childValue3" name="childValue3" placeholder="子组件的输入框">
<button (click)="childFunction3()" nz-button nzType="primary">调用方法</button>
childValue3;
childFunction3() {
this.messageService.info(this.childValue3);
}
子组件传值给父组件
在父组件传值给子组件的时候,其实是通过指令的方式完成的.但是使用指令的前提,是被传值者是一个标签,这符合了父组件传值给子组件的条件.
但是子组件显然不可能包含父组件的标签,所以并不能通过这种方式完成传值.
父组件html+ts
<h1>我是父组件</h1>
<input nz-input class="input" [(ngModel)]="name" placeholder="姓名">
<input nz-input class="input" [(ngModel)]="bornYear" placeholder="出生年月">
<child-communication (event)="showInfo($event)"></child-communication>
name;
bornYear;
showInfo($event) {
this.name = $event.name;
this.bornYear = $event.bornYear;
}
子组件html+ts
<h1>我是子组件</h1>
<input nz-input class="input" [(ngModel)]="name" name="name" placeholder="姓名">
<input nz-input class="input" [(ngModel)]="bornYear" name="bornYear" placeholder="出生年月">
<button (click)="childFunction4()" nz-button nzType="primary">传值给父组件</button>
@Output() event = new EventEmitter<any>();
name = 'Eve';
bornYear = '1995';
childFunction4() {
this.event.emit(
{
name: this.name,
bornYear: this.bornYear
}
);
}
通过服务进行通讯
在组件通讯中,还有一种方式叫做服务(service).这种方式较为复杂,涉及RxJS内容,具体步骤如下:
- 定义一个service,定义父子Subject变量,转为Observable后再保存变量,创建函数事件发射器
- 在父组件中, 在 providers中提供服务的实例,在构造函数中对子组件发起订阅
- 在子组件中,重复上一步,只是没有使用 providers,因为是子组件,可以自动获取父组件的服务实例
- 点击按钮(无论是父的还是子的),都会触发服务中的 next()函数,发送新值给订阅者,订阅者触发订阅操作,将新值赋值给自身的成员变量,之后的刷新试图操作属于双向绑定,与通讯无关.
Service
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable()
export class CommunicationService {
// 声明两个Subject并定义接收数据类型,在本案例中是一个对象
private father = new Subject<{ drink, eat }>();
private child = new Subject<{ drink, eat }>();
// 将Subject转化为Observable
father$ = this.father.asObservable();
child$ = this.child.asObservable();
/* 将变化的值,发送给订阅者 */
fatherSend(value: { drink, eat }) {
this.father.next(value);
}
childSend(value: { drink, eat }) {
this.child.next(value);
}
}
父组件html+ts
<h1>父组件</h1>
<input nz-input class="input" [(ngModel)]="drink" name="drink" placeholder="最爱喝的饮料">
<input nz-input class="input" [(ngModel)]="eat" name="eat" placeholder="最爱吃的甜点">
<button (click)="transferDataByService()" nz-button nzType="primary">传值给子组件</button>
<child-communication></child-communication>
import { CommunicationService } from './service/communication.service';
import { Subscription } from 'rxjs';
@Component({
templateUrl: './component-communication.component.html',
styleUrls: ['./component-communication.component.less'],
providers: [CommunicationService]
})
export class ComponentCommunicationComponent implements OnDestroy {
subscription: Subscription;
constructor(
private communicationService: CommunicationService
) {
this.subscription = communicationService.child$.subscribe(value => {
this.drink = value.drink;
this.eat = value.eat;
});
}
drink = '奶茶';
eat = '泡芙';
transferDataByService() {
this.communicationService.fatherSend({ drink: this.drink, eat: this.eat });
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
子组件html+ts
<h1>子组件</h1>
<input nz-input class="input" [(ngModel)]="drink" name="drink" placeholder="最爱喝的饮料">
<input nz-input class="input" [(ngModel)]="eat" name="eat" placeholder="最爱吃的甜点">
<button (click)="transferDataByService()" nz-button nzType="primary">传值给父组件</button>
import { Subscription } from 'rxjs';
@Component({
selector: 'child-communication',
templateUrl: './child-communication.component.html',
styleUrls: ['./child-communication.component.less']
})
export class ChildCommunicationComponent implements OnDestroy {
subscription: Subscription;
constructor(private communicationService: CommunicationService) {
this.subscription = communicationService.father$.subscribe(value => {
this.drink = value.drink;
this.eat = value.eat;
});
}
drink;
eat;
transferDataByService() {
this.communicationService.childSend({ drink: this.drink, eat: this.eat });
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
组件样式
在父组件当中定义了样式 bgColor,将背景颜色设置为红色,在子组件当中定义了样式 color将字体颜色设置为蓝色.在父子组件的内容中,同时应用了这两种样式,通过效果可以发现,父子组件样式互相并不影响.

8182

被折叠的 条评论
为什么被折叠?



