Angular的核心思想就是组件话,我们可以将组件做成一个独立的应用模块来使用。实际开发过程中,我们会发现在应用中有很多功能可以抽象化,可以复用。
想要把一个通用的功能封装成组件,实现功能复用,那么我们的组件就需要有输入、输出,这就是组件交互。
输入型属性
在Angular中,我们使用@Input装饰器来为组件创建输入型属性。
我们定义一个DemoComponent,包含两个输入型属性:
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-demo',
template: `
<p>name值为: {{name}}</p>
<p>masterName值为:{{masterName}}</p>
`
})
export class DemoComponent {
@Input() name: string;
@Input('master') masterName: string;
}
第一个输入属性是name。
第二个输入属性是masterName,通过@Input装饰器,我们为该属性指定了一个别名master。
这样,组件的输入型属性我们就定义完成了。
我们接下来就可以在html中使用demo组件:
<app-demo name="Angular" master="真棒!"></app-demo>
输入属性setter截听
使用一个输入属性的setter,可以截听从父组件传过来的属性内容,并做相应处理。
Demo2Component的输入属name上使用setter,使用trim方法,trim掉输入的空格,并把空值替换成默认字符串。
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-demo2',
template: '<h3>"{{name}}"</h3>'
})
export class Demo2Component {
private _name = '';
@Input()
set name(name: string) {
this._name = (name && name.trim()) || '没有输入';
}
get name(): string { return this._name; }
}
在父组件中使用方式还是和上面一样:
<app-demo2 name=" 我前面有空格"></app-demo2>
<app-demo2 name="我后面后空格"></app-demo2>
<app-demo2 name=" "></app-demo2>
实际渲染效果如下:
我前面有空格
我后面后空格
没有输入
ngOnChanges()
使用OnChanges生命周期钩子接口ngOnChanges()方法来监测输入属性值的变化并做出相应处理。
组件所有输入属性的变更都会被OnChanges生命周期钩子捕获到。
这个 VersionChildComponent 会监测输入属性 major 和 minor 的变化,并把这些变化编写成日志以报告这些变化。
import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
@Component({
selector: 'app-version-child',
template: `
<h3>Version {{major}}.{{minor}}</h3>
<h4>Change log:</h4>
<ul>
<li *ngFor="let change of changeLog">{{change}}</li>
</ul>
`
})
export class VersionChildComponent implements OnChanges {
@Input() major: number;
@Input() minor: number;
changeLog: string[] = [];
ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
let log: string[] = [];
for (let propName in changes) {
let changedProp = changes[propName];
let to = JSON.stringify(changedProp.currentValue);
if (changedProp.isFirstChange()) {
log.push(`Initial value of ${propName} set to ${to}`);
} else {
let from = JSON.stringify(changedProp.previousValue);
log.push(`${propName} changed from ${from} to ${to}`);
}
}
this.changeLog.push(log.join(', '));
}
}
VersionParentComponent 提供 minor 和 major 值,把修改它们值的方法绑定到按钮上。
import { Component } from '@angular/core';
@Component({
selector: 'app-version-parent',
template: `
<h2>Source code version</h2>
<button (click)="newMinor()">New minor version</button>
<button (click)="newMajor()">New major version</button>
<app-version-child [major]="major" [minor]="minor"></app-version-child>
`
})
export class VersionParentComponent {
major = 1;
minor = 23;
newMinor() {
this.minor++;
}
newMajor() {
this.major++;
this.minor = 0;
}
}
下面是点击按钮的结果。
输出型属性
就像我们的方法一样,有输入参数,有返回值。同样,我们的组件交互也需要有返回值(即输出型属性)。通过输出型属性,我们可以就将子组件的内容反馈给父组件,从而实现从子组件到父组件的交互。
在Angular中,我们使用@Output来标识一个输出型属性,输出型属性都需要定义成EventEmitter类型。
@Output change: EventEmitter<boolean> = new EventEmitter<boolean>();
在父组件中使用 ()
来绑定子组件的输出型属性:
<app-child (change)="doChange($event)"></app-child>
$event
的类型就是子组件中EventEmitter的泛型值boolean。
在子组件的中通过change属性传值:
this.change.emit(true);
这样我们的父组件中的doChange中就可以获取true值:
doChange(event: boolean) {
// 此时的event就是true
console.log(event);
}
// 浏览器空时