父传子
父组件向子组件传值,主要是使用到了@Input
例子:
父组件:
//app.component.html
<app-child [childMsg]="parentMsg"></app-child>
//app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
parentMsg = 'parent component message!';
}
子组件:
//child.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
})
export class ChildComponent {
@Input() childMsg: string = '';
}
// child.component.html
<div>父组件传递的内容:{{ childMsg }}</div>
子传父
子组件使用@Output
装饰器允许数据从子组件传给父组件。为了引发事件,@Input()
必须是EventEmitter
类型,它是@agular/core中用来发出自定义事件的类。
例子:
父组件
// app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
items = ['item1', 'item2', 'item3'];
addItem(newItem: string) {
this.items.push(newItem);
}
}
// app.component.html
<app-child (newItemEvent)="addItem($event)"></app-child>
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
子组件
//child.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
})
export class ChildComponent {
@Output() newItemEvent = new EventEmitter<string>();
addNewItem(value: string) {
this.newItemEvent.emit(value);
}
}
//child.component.html
<label>输入项目名:<input type="text" #newItem /></label>
<button type="button" (click)="addNewItem(newItem.value)">
添加项目到父组件
</button>
实现的效果如下:
本地变量
父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法。例子如下:
子组件
//child.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css'],
})
export class ChildComponent {
count: number = 0;
add() {
this.count++;
}
decrease() {
this.count--;
}
}
父组件
// app.component.html
<app-child #child></app-child>
<button type="button" (click)="child.add()">加一</button>
<button type="button" (click)="child.decrease()">减一</button>
<span>{{ child.count }}</span>
最后的结果如下:
本地变量的局限性
由于父组件和子组件的连接必须全部在父组件的模板中进行,父组件本身的代码对子组件没有访问权。换句话说,在子组件标签中通过#+变量名
的方式新建一个本地变量代表子组件的引用。本地变量方式使用简单明了,但也有局限性,只能在模板html中使用,无法在ts文件中使用。
@ViewChild
通过@ViewChild
装饰器,将子组件注入到父组件。
例子
父组件
// app.component.html
<app-child></app-child>
<button type="button" (click)="add(2)">加2</button>
// app.component.ts
import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child/child.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
@ViewChild(ChildComponent) private Child: ChildComponent;
add(num: number) {
this.Child.add(num);
}
}
子组件
// child.component.ts
import { Component} from '@angular/core';
@Component({
selector: 'app-child',
template: '<span>{{count}}</span>',
styleUrls: ['./child.component.css'],
})
export class ChildComponent {
count: number = 0;
add(num: number) {
this.count = this.count + num;
}
}
效果如下:
通过服务来通信
组件之间共享一个service服务,那么组件之间就可以通过service实现通信 。
创建两个不相关的组件A和B,通过服务文件data.service.ts进行关联。
首先,创建data.service.ts
//创建service命令
ng g service data
// data.service.ts
import { Injectable } from '@angular/core';
// 1.引入
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class DataService {
// 2.创建subject
subject: BehaviorSubject<any> = new BehaviorSubject<any>(0);
constructor() {}
}
需要在app.module.ts文件中引入公共data.service.ts文件,并声明。
// app.module.ts
import { DataService } from './data.service';
@NgModule({
providers: [DataService],
})
export class AppModule {}
其次,创建组件A,用于发布数据
//创建组件A命令
ng generate component A
// a.component.ts
import { Component } from '@angular/core';
// 1. 引入
import { DataService } from '../data.service';
@Component({
selector: 'app-a',
templateUrl: './a.component.html',
})
export class AComponent {
// 2. 注册
constructor(public dataService: DataService) {}
inputValue: string = '';
send(): void {
// 3. 发布
this.dataService.subject.next(this.inputValue);
}
}
// a.component.html
<label>A组件</label>
<input type="text" [(ngModel)]="inputValue" />
<button type="button" (click)="send()">发送数据</button>
创建组件B,用于接收数据。
//创建组件B命令
ng generate component B
//b.component.ts
import { Component } from '@angular/core';
// 1. 引入
import { Subscription } from 'rxjs';
import { DataService } from '../data.service';
@Component({
selector: 'app-b',
templateUrl: './b.component.html',
})
export class BComponent {
data: any;
// 2. subscription
subscription: Subscription;
constructor(public dataService: DataService) {
// 3. 订阅
this.subscription = this.dataService.subject.subscribe((data) => {
this.data = data;
});
}
ngOndestry(): void {
// 4. 取消订阅
this.subscription.unsubscribe();
}
}
//b.component.html
<label>B组件接收到的数据:</label>
<span>{{ data }}</span>
// app.component.html
<app-a></app-a>
<br />
<app-b></app-b>
实现的效果如下: