更新时间 - 2017-03-22html
Input 是属性装饰器,用来定义组件内的输入属性。在实际应用场合,咱们主要用来实现父组件向子组件传递数据。Angular 应用是由各式各样的组件组成,当应用启动时,Angular 会从根组件开始启动,并解析整棵组件树,数据由上而下流下下一级子组件。typescript
counter.component.tssegmentfault
import { Component, Input } from '@angular/core'; @Component({ selector: 'exe-counter', template: ` <p>当前值: {{ count }}</p> <button (click)="increment()"> + </button> <button (click)="decrement()"> - </button> ` }) export class CounterComponent { @Input() count: number = 0; increment() { this.count++; } decrement() { this.count--; } }
app.component.ts浏览器
import { Component } from '@angular/core'; @Component({ selector: 'exe-app', template: ` <exe-counter [count]="initialCount"></exe-counter> ` }) export class AppComponent { initialCount: number = 5; }
以上代码运行后浏览器显示的结果:app
Input 装饰器支持一个可选的参数,用来指定组件绑定属性的名称。若是没有指定,则默认使用 @Input 装饰器,装饰的属性名。具体示例以下:ide
counter.component.ts函数
import { Component, Input } from '@angular/core'; @Component({ selector: 'exe-counter', template: ` <p>当前值: {{ count }}</p> <button (click)="increment()"> + </button> <button (click)="decrement()"> - </button> ` }) export class CounterComponent { @Input('value') count: number = 0; ... // 其他代码未改变 }
app.component.tsui
import { Component } from '@angular/core'; @Component({ selector: 'exe-app', template: ` <exe-counter [value]="initialCount"></exe-counter> ` }) export class AppComponent { initialCount: number = 5; }
import { Component, Input } from '@angular/core'; @Component({ selector: 'exe-counter', template: ` <p>当前值: {{ count }}</p> <button (click)="increment()"> + </button> <button (click)="decrement()"> - </button> `, inputs:['count:value'] // 类成员属性名称:绑定的输入属性名称 }) export class CounterComponent { count: number = 0; increment() { this.count++; } decrement() { this.count--; } }
setter 和 getter 是用来约束属性的设置和获取,它们提供了一些属性读写的封装,可让代码更便捷,更具可扩展性。经过 setter 和 getter 方式,咱们对类中的私有属性进行了封装,能避免外界操做影响到该私有属性。此外经过 setter 咱们还能够封装一些业务逻辑,具体示例以下:this
counter.component.tsspa
import { Component, Input } from '@angular/core'; @Component({ selector: 'exe-counter', template: ` <p>当前值: {{ count }} </p> <button (click)="increment()"> + </button> <button (click)="decrement()"> - </button> ` }) export class CounterComponent { _count: number = 0; // 默认私有属性如下划线开头,不是必须也可使用$count biggerThanTen: boolean = false; @Input() set count (num: number) { this.biggerThanTen = num > 10; this._count = num; } get count(): number { return this._count; } increment() { this.count++; } decrement() { this.count--; } }
当数据绑定输入属性的值发生变化的时候,Angular 将会主动调用 ngOnChanges 方法。它会得到一个 SimpleChanges 对象,包含绑定属性的新值和旧值,它主要用于监测组件输入属性的变化。具体示例以下:
import { Component, Input, SimpleChanges, OnChanges } from '@angular/core'; @Component({ selector: 'exe-counter', template: ` <p>当前值: {{ count }}</p> <button (click)="increment()"> + </button> <button (click)="decrement()"> - </button> ` }) export class CounterComponent implements OnChanges{ @Input() count: number = 0; ngOnChanges(changes: SimpleChanges) { console.dir(changes['count']); } increment() { this.count++; } decrement() { this.count--; } }
以上代码运行后浏览器显示的结果:
上面例子中须要注意的是,当手动改变输入属性的值,是不会触发 ngOnChanges
钩子的。
1.在构造函数中是获取不到输入属性的值
在子组件的构造函数中,是没法获取输入属性的值,只能在 ngOnChanges 或 ngOnInit 钩子中获取到。由于子组件的构造函数会优先执行,当子组件输入属性变化时会自动调用 ngOnChanges 钩子,而后在调用 ngOnInit 钩子,因此在 ngOnInit 钩子内能获取到输入的属性。
具体详情可参考 - Angular 2 constructor & ngOnInit
2.不能同时使用 @Input 装饰器 或在 @Directive、@Component inputs 字段中定义同一个输入属性,具体示例以下:
@Component({ selector: 'exe-counter', inputs:['count:value'] }) export class CounterComponent { @Input('value') count: number = 0; }
3.@Input vs inputs
相同点:
它们都是用来定义输入属性
异同点:
inputs 定义在指令的 metadata 信息中,开发者对指令的输入属性一目了然。此外对于未选用 TypeScript 做为开发语言的开发者,也只能在 metadata 中定义指令的输入属性。
@Input 属于属性装饰器,经过它咱们能够一块儿定义属性的访问描述符 (public、private、protected):
@Input() public attr: string;
4.输入、输出属性风格指南
4.1 坚持使用 @Input 和 @Output ,而非 @Directive 和 @Component 装饰器的 inputs 和 outputs 属性:
易于在类里面识别哪些属性是输入属性或输出属性。
4.2 坚持把 @Input 或者 @Output 放到所装饰的属性的同一行:
若是须要重命名与@Input
或者@Output
关联的属性或事件名,你能够在一个位置修改。
4.3 避免为输入和输出属性指定别名
同一个属性有两个名字(一个对内一个对外)很容易致使混淆。
详细信息请参考 - Angular 2 风格指南 - STYLE 05-12
5.项目开发中尽可能经过 @Input 装饰器定义无状态的组件,即组件仅依赖于输入属性,这样会大大提升组件可复用性