Angular中的 EventEmitter、@Output、@Input、OnChanges

本文详细介绍了Angular中用于组件间通信的EventEmitter类,以及如何使用@Output装饰器将数据从子组件发送到父组件。同时讨论了父组件如何通过@Input修饰的属性修改子组件数据,并分析了监视@Input()变化的两种方法:setter拦截器和OnChanges生命周期钩子。此外,还提到了ngOnChanges钩子和SimpleChanges对象在变更检测中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

EventEmitter 类

EventEmitter用在带有 @Output 指令的组件中,以同步或异步方式发出自定义事件,并通过订阅实例来为这些事件注册处理器。

// EventEmitter类 继承自Rxjs的Subject。(EventEmitter 类派生自 Observable。)
class EventEmitter<T> extends Subject<T> {

  /**
   * 构造函数,用于创建此类的实例,该实例可以同步或异步发送事件。
   * isAsync 默认值为false,表示同步传递事件。为 true 时,异步传递事件。
   * 泛型T,表示要发射的值和被订阅的值类型
   */
  constructor(isAsync?: boolean): EventEmitter<T>
  
  // 发出包含给定值的事件。value为要发出的值,类型为T。
  emit(value?: T): void
  
  // 注册此实例发出的事件的处理器。
  subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription
  
}

使用 EventEmitter 自定义事件

Directives(指令) 通常使用 Angular 的 EventEmitter 引发自定义事件:

  • 该指令创建一个 EventEmitter 并将其对外暴露为属性。
  • 该指令调用 EventEmitter.emit(data) 发出事件,传入消息数据,该消息数据可以是任何东西。
  • 父指令通过绑定到该属性来监听事件,并通过传入的 $event 对象接收数据。

子组件把数据发送到父组件 @Output、EventEmitter

@Output() 在子组件中标记了一个属性,作为数据从子组件传递到父组件的途径。

子组件使用 @Output() 属性来引发事件,以通知父组件这一变化。为了引发事件, @Output() 必须是 EventEmitter 类型,它是 @angular/core 中用来发出自定义事件的类。

// 子组件
import { Output, EventEmitter } from '@angular/core';
export class ItemOutputComponent {
  /**
   * @Output() -  一个装饰器函数,它把该属性标记为数据从子组件进入父组件的一种途径
   * newItemEvent - 这个 @Output() 的名字
   * EventEmitter<string> - 这个 @Output() 的类型
   * new EventEmitter<string>() - 使用 Angular 来创建一个新的事件发射器,它发出的数据是 string 类型的。
   */
  @Output() newItemEvent = new EventEmitter<string>();

  addNewItem(value: string) {
    this.newItemEvent.emit(value);
  }
}

// 子组件模板
<label for="item-input">Add an item:</label>
<input type="text" id="item-input" #newItem>
<button (click)="addNewItem(newItem.value)">Add to parent's list</button>
// 父组件
export class AppComponent {
  items = ['item1', 'item2', 'item3', 'item4'];

  addItem(newItem: string) {
    this.items.push(newItem);
  }
}

// 父组件模板中 使用子组件
<app-item-output (newItemEvent)="addItem($event)"></app-item-output>

父组件修改子组件中的数据 @Input

子组件或指令中的 @Input() 装饰器表示该属性可以从其父组件中获取值。

/**
 * 父组件模板
 * 使用子组件的 selector (<app-item-detail>) 作为父组件模板中的指令。
 * 使用属性绑定把子组件的 item 属性绑定到父组件的 currentItem 属性上。
 */
<app-item-detail [item]="currentItem"></app-item-detail>

// 父组件
export class AppComponent {
  currentItem = 'Television';
}
// 子组件模板
<p>
  Today's item: {{item}}
</p>

// 子组件
import { Component, Input } from '@angular/core';
export class ItemDetailComponent {
  @Input() item = '';
}

监视 @Input() 的变更的两种方式

方式一:setter拦截器

// 子组件模板
<p>
  Today's item: {{_item}}
</p>

// 子组件
import { Component, Input } from '@angular/core';
export class ItemDetailComponent {
  _item: string = '';
  
    @Input() set item(value: string){
        this._item = value;
        
        // 每当数据发送改变时要执行的操作
        this.valueChangeHandler()
    };

    valueChangeHandler() {
        console.log('数据被父组件更改了,我应该相应地做点别的操作!');
    }
}

方式二:OnChanges生命钩子

// 子组件模板
<p>
  Today's item: {{item}}
</p>

// 子组件
import { Component, Input, OnChanges, SimpleChanges, } from '@angular/core';
export class ItemDetailComponent {
  @Input() item = '';

  ngOnChanges(changes: SimpleChanges) {
     console.log('item的最新值:', changes.item.currentValue, 'item的旧值:', changes.item.previousValue;)
     // 每当数据发送改变时要执行的操作
     this.valueChangeHandler()
  }
  
  valueChangeHandler() {
     console.log('数据被父组件更改了,我应该相应地做点别的操作!');
  }
}

ngOnChanges钩子和SimpleChanges对象

在Angular生命周期钩子的执行顺序中,ngOnChanges()排在第一位。

生命钩子用途时机注意事项
ngOnChanges()ngOnChanges()是一个生命周期钩子,当组件或指令的任何一个可绑定属性(输入属性)发生变化时调用。 定义一个 ngOnChanges() 方法来处理这些变更。

当 Angular 设置或重新设置数据绑定的输入属性时响应。 该方法接受当前和上一属性值的 SimpleChanges 对象。

ngOnChanges() 方法获取了一个对象,它把每个发生变化的属性名都映射到了一个SimpleChange对象, 该对象中有属性的当前值和前一个值。这个钩子会在这些发生了变化的属性上进行迭代,并记录它们。
如果组件绑定过输入属性,那么在 ngOnInit() 之前以及所绑定的一个或多个输入属性的值发生变化时都会调用。

如果至少发生了一次变更,则该回调方法会在默认的变更检测器检查完可绑定属性之后、视图子节点和内容子节点检查完之前调用。
1. OnChanges发生的非常频繁,所以你在这里执行的任何操作都会显著影响性能。

2. 如果你的组件没有输入属性,或者你使用它时没有提供任何输入属性,那么框架就不会调用 ngOnChanges()。

3. 当输入属性的引用发生改变时,才会触发钩子ngOnChanges()。比如说,如果输入属性是一个对象hero: Hero,而父组件只修改了hero.name的值,则不会触发子组件的ngOnChanges()。

SimpleChanges:用 SimpleChange 对象表示的变更的哈希表。

export declare interface SimpleChanges {
    [propName: string]: SimpleChange;
}

export declare class SimpleChange {
    previousValue: any; 
    currentValue: any;
    firstChange: boolean; 
    constructor(previousValue: any, currentValue: any, firstChange: boolean);
    // 检查新值是否是首次赋值的。
    isFirstChange(): boolean;
}

组件要如何实现本接口来定义一个输入属性的变更处理器?

@Component({selector: 'my-cmp', template: `...`})
class MyComponent implements OnChanges {
  // 输入属性
  @Input() prop: number = 0;
  // 变更处理器
  ngOnChanges(changes: SimpleChanges) {
    // changes.prop contains the old and the new value...
  }
}

使用变更检测钩子

https://angular.cn/guide/lifecycle-hooks#using-change-detection-hooks

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值