@Output

组件或指令需要发出变化通知,这是理所当然的。

长什么样?

通过 @Output() 装饰器,告知这个属性允许发出变化通知。

@Component({
  selector: 'user-detail',
  template: `
  user id: {{userId}}
  <button (click)="onDelete()">delete</button>`
})
export class UserDetailComponent {
  @Input() userId: number;
  @Output() delete = new EventEmitter<number>();

  onDelete() {
    this.delete.emit(this.user.id);
  }
}

于是,需要用到 user-detail 组件,都可以向它传递一个 delete 事件绑定。

@Component({
  selector: 'user-list',
  template: `<user-detail userId="1" (delete)="onDelete($event)">`
})
export class UserListComponent {
  @Output() delete = new EventEmitter<number>();

  onDelete(uid: number) {
      console.log(uid);
  }
}

属性太难看了

@Input() 一样,支持重新指定一个新的属性名。

@Output('delete') delete = new EventEmitter<number>();

什么是EventEmitter<T>?

触发组件或指令中的自定义事件。意思就是说,它只是用来触发外部定义的函数而已,没有别的意思。

注:它完全不同于Node的EventEmitter。

EventEmitter<T> 的本质是一个 Subject,这是RxJs方面的知识,会在RxJS章节继续说明。

参数

细心你会发现,我一直写的 EventEmitter<T>,它是一个泛型类型对象。

看下面一个(错误)示例:

@Output() delete = new EventEmitter<number, string>();

当你希望事件允许有多个参数时,以上的定义是错误的,因为只允许一个参数,这个细节点一定要记住!因此,如果你希望向外传递多个参数时,只需要将它们组合成一个对象即可。

@Output() delete = new EventEmitter<any>();

delete.emit({ id: 1, name: 'cipchk' });

如何处理dom事件

有时候当我们需要点击事件后并阻止默认行为时(即调用 event.preventDefault()),就需要在模板中设置 $event 参数。

<user-detail userId="1" (delete)="onDelete($event)">

实际上 $event 就是指DOM Event 对象。因此,可以组件类这么处理:

onDelete(event: Event) {
  event.preventDefault();
}

处理Event对象与参数并存

前面我说过 EventEmitter<T> 只接收一个参数,这意味者,没有必须接收两个参数,即 Event 对象和业务参数,那怎么办呢?

其实我们可以换个角度来想,对于 user-detail 组件的 delete 自定义事件而言,其触发在其组件内,而非调用方(即:UserListComponent)。所以类似这种情况,应该在其组件内进行处理。

@Component({
  selector: 'user-detail',
  template: `
  user id: {{userId}}
  <button (click)="onDelete($event)">delete</button>`
})
export class UserDetailComponent {
  @Input() userId: number;
  @Output() delete = new EventEmitter<number>();

  onDelete(event: Event) {
    event.preventDefault();
    this.delete.emit(this.user.id);
  }
}

不要在Service中使用 EventEmitter<T>

前面我说过【触发组件或指令中的自定义事件】,虽然其本质是继承RxJs的 Subject,但Angular会对其更进一步抽象。

如果你需要在Service中那么请用RxJs相关方法,例如:Subject

results matching ""

    No results matching ""