视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Angular中Input和Output的介绍(附代码)
2020-11-27 19:27:11 责编:小采
文档


本篇文章给大家带来的内容是关于Angular中Input和Output的介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

Input 是属性装饰器,用来定义组件内的输入属性。在实际应用场合,我们主要用来实现父组件向子组件传递数据。Angular 应用是由各式各样的组件组成,当应用启动时,Angular 会从根组件开始启动,并解析整棵组件树,数据由上而下流下下一级子组件。

@Input()

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() 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;
}

@Input(‘bindingPropertyName’)

Input 装饰器支持一个可选的参数,用来指定组件绑定属性的名称。如果没有指定,则默认使用 @Input 装饰器,装饰的属性名。具体示例如下:

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.ts

import { Component } from '@angular/core';
@Component({
 selector: 'exe-app',
 template: `
 <exe-counter [value]="initialCount"></exe-counter>
 `
})
export class AppComponent {
 initialCount: number = 5;
}

setter & getter

setter 和 getter 是用来约束属性的设置和获取,它们提供了一些属性读写的封装,可以让代码更便捷,更具可扩展性。通过 setter 和 getter 方式,我们对类中的私有属性进行了封装,能避免外界操作影响到该私有属性。此外通过 setter 我们还可以封装一些业务逻辑,具体示例如下:

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 {
 _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--;
 }
}

ngOnChanges

当数据绑定输入属性的值发生变化的时候,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 钩子的。

Output 是属性装饰器,用来定义组件内的输出属性。前面我们介绍了 Input 装饰器的作用,也了解了当应用启动时,Angular 会从根组件开始启动,并解析整棵组件树,数据由上而下流下下一级子组件。而我们今天介绍的 Output 装饰器,是用来实现子组件将信息通过事件的形式通知到父级组件。

在介绍 Output 属性装饰器前,我们先来介绍一下 EventEmitter 这个幕后英雄。它用来触发自定义事件,具体使用示例如下:

let numberEmitter: EventEmitter<number> = new EventEmitter<number>(); 
numberEmitter.subscribe((value: number) => console.log(value));
numberEmitter.emit(10);

在 Angular 中的 EventEmitter 应用场景是:

子指令创建一个 EventEmitter 实例,并将其作为输出属性导出。子指令调用已创建的 EventEmitter 实例中的 emit(payload) 方法来触发一个事件,父指令通过事件绑定 (eventName) 的方式监听该事件,并通过 $event 对象来获取 payload 对象。是不是感觉有点抽象,我们马上实战一下。

@Output()

counter.component.ts
import { Component, Input, Output, EventEmitter } 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;
 @Output() change: EventEmitter<number> = new EventEmitter<number>();
 increment() {
 this.count++;
 this.change.emit(this.count);
 }
 decrement() {
 this.count--;
 this.change.emit(this.count);
 }
}

app.component.ts

import { Component } from '@angular/core';
@Component({
 selector: 'exe-app',
 template: `
 <p>{{changeMsg}}</p> 
 <exe-counter [count]="initialCount" 
 (change)="countChange($event)"></exe-counter>
 `
})
export class AppComponent {
 initialCount: number = 5;
 changeMsg: string;
 countChange(event: number) {
 this.changeMsg = `子组件change事件已触发,当前值是: ${event}`;
 }
}

@Output(‘bindingPropertyName’)

Output 装饰器支持一个可选的参数,用来指定组件绑定属性的名称。如果没有指定,则默认使用 @Output 装饰器,装饰的属性名。具体示例如下:

counter.component.ts

import { Component, Input, Output, EventEmitter } 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;
 @Output('countChange') change: EventEmitter<number> = new EventEmitter<number>();
... // 其余代码未改变
}

app.component.ts

import { Component } from '@angular/core';
@Component({
 selector: 'exe-app',
 template: `
 <p>{{changeMsg}}</p> 
 <exe-counter [count]="initialCount" 
 (countChange)="countChange($event)"></exe-counter>
 `
})
export class AppComponent {
 initialCount: number = 5;
 changeMsg: string;
 countChange(event: number) {
 this.changeMsg = `子组件change事件已触发,当前值是: ${event}`;
 }
}

双向绑定

在介绍双向绑定之前,我们先来说个需求:即在 CounterComponent 子组件 count 值发生变化的时候,需同步更新 AppComponent 父组件中的 initialCount 的值。通过上面的实例,我们知道我们可以在 AppComponent 父组件中监听 CounterComponent 子组件的 change 事件,然后在 change 事件中更新 initialCount 的值。具体示例如下:

counter.component.ts

import { Component, Input, Output, EventEmitter } 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;
 @Output() change: EventEmitter<number> = new EventEmitter<number>();
 increment() {
 this.count++;
 this.change.emit(this.count);
 }
 decrement() {
 this.count--;
 this.change.emit(this.count);
 }
}

app.component.ts

import { Component } from '@angular/core';
@Component({
 selector: 'exe-app',
 template: `
 <p>父组件当前值:{{ initialCount }}</p> 
 <exe-counter [count]="initialCount" 
 (change)="initialCount = $event"></exe-counter>
 `
})
export class AppComponent {
 initialCount: number = 5;
}

其实双向绑定是由两个单向绑定组成:

模型 -> 视图数据绑定

视图 -> 模型事件绑定

Angular 中 [] 实现了模型到视图的数据绑定,() 实现了视图到模型的事件绑定。把它们两个结合在一起 [()] 就实现了双向绑定。也被称为 banana in the box 语法。

[()] 语法示例

counter.component.ts

import { Component, Input, Output, EventEmitter } 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;
 // 
输出属性名称变更: change -> countChange @Output() countChange: EventEmitter<number> = new EventEmitter<number>(); ... // 其余代码未改变 }

app.component.ts

import { Component } from '@angular/core';
@Component({
 selector: 'exe-app',
 template: `
 <p>父组件当前值:{{ initialCount }}</p> 
 <exe-counter [(count)]="initialCount"></exe-counter>
 `
})
export class AppComponent {
 initialCount: number = 5;
}

从上面可以看出,[(modelName)] 可以拆分成两部分 modelName 和 modelNameChange ,[modelName] 用于绑定输入属性,(modelNameChange) 用于绑定输出属性。当 Angular 在解析模板时,遇到 [(modelName)] 形式的绑定语法,它会期待这个指令中会存在一个名为 modelName 的输入属性和一个名为 modelNameChange 的输出属性。

ngModel

使用过 Angular 1.x 的读者,应该很熟悉 ng-model 这个指令,我们通过它来实现数据的双向绑定。那么在 Angular 中有对应的指令么 ?答案是有滴,它就是 ngModel 指令。

ngModel双向绑定示例

import { Component } from '@angular/core';
@Component({
 selector: 'exe-app',
 template: `
 <p>你输入的用户名是:{{ username }}</p> 
 <input type="text" [(ngModel)]="username" />
 `
})
export class AppComponent {
 username: string = '';
}

ngModel表单验证示例

import { Component } from '@angular/core';
@Component({
 selector: 'exe-app',
 styles:[
 `.error { border: 1px solid red;}`
 ],
 template: `
 <p>你输入的用户名是:{{ username }}</p>
 <input type="text" 
 [(ngModel)]="username" 
 #nameModel="ngModel" 
 [ngClass]="{error: nameModel.invalid}"
 required/>
 {{nameModel.errors | json}}
 `
})
export class AppComponent {
 username: string = '';
}

以上示例利用 @Directive 指令 metadata 信息中的 exportAs 属性,获取 ngModel 实例,进行获取控件的状态,控件状态分类如下:

valid - 表单值有效

pristine - 表单值未改变

dirty - 表单值已改变

touched - 表单已被访问过

untouched - 表单未被访问过

下载本文
显示全文
专题