Angular框架专题

Angular框架的事件冒泡(Event Modifiers)以

2021-11-29  本文已影响0人  听书先生

Dom元素会通过一些事件通过Dom的层级结构进行传播,这种传播的过程叫做事件冒泡,事件冒泡是指的最内层的事件类型触发导致了父级的Dom触发了相同的事件类型事件,由内到外的一个过程,而由外到内指的是事件捕获。

import { Component } from "@angular/core";

@Component({
  selector:'my-component',
  template:`
   <div (click)="handleClick()">
      <button >点击</button>
   </div> 
  `
})

export class AppComponent {
  handleClick() {
    console.log('触发了点击事件...');
  }
}

上述表示div的盒子添加点击事件后被执行。

angular中组件使用事件冒泡

在angular中,我们能使用@Output装饰器和EventEmitter自定义事件,它不同于Dom事件,因为它不支持事件冒泡。
比如我们先自定义一个组件:

import { Component } from '@angular/core';

@Component({
    selector: 'test-com',
    template: `
    <div>
      <button>Click</button>
    </div>
  `
})
export class TestComComponent { }

在主程序中使用自定义的组件作为子组件进行使用。

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <test-com (click)="handleClick()"></test-com>
    </div>
  `
})
export class AppComponent {
  handleClick() {
    console.log('Click');
  }
}

这种情况下可以看到依旧是正常输出的,表示我们在触发点击事件时,触发的是添加在子组件上的click事件,但是如果此时我们的子组件中也有click点击事件呢?
修改上面的自定义组件的代码:

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
    selector: 'test-com',
    template: `
    <div>
      <button (click)="handleClick('child')">Click child</button>
    </div>
  `
})
export class TestComComponent { 
    @Output() click = new EventEmitter();

    handleClick(button: string) {
        this.click.next(button);
    }
}
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <test-com (click)="handleClick($event)"></test-com>
    </div>
  `
})
export class AppComponent {
  handleClick(event: any) {
    console.log(event);
  }
}

当点击Click child时,Angular内部会处理自定义事件和DOM事件,当Click事件触发后,handleClick方法接收的参数是MouseEvent对象。
那么可以直接在点击事件时添加stopPropagation()方法

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
    selector: 'test-com',
    template: `
    <div>
      <button (click)="handleClick('child')">Click child</button>
    </div>
  `
})
export class TestComComponent { 
    @Output() click = new EventEmitter();

    handleClick(event: Event, button: string) {
        event.stopPropagation();
        this.click.next(button);
    }
}

DOM元素的冒泡机制,允许父元素去监听子元素触发的事件,在Angular框架中,虽然可以直接使用stopPropagation直接解决问题,但是实际开发中,并不建议这么操作。

Event Modifiers

在dom元素中,两种情形需要注意的点,一种是会触发默认事件,则使用preventDefault()取消事件的所有默认行为,一种是事件冒泡,使用stopPropagation()阻止当前事件在Dom上的冒泡。
在Angular中阻止事件冒泡的写法大致有几种:

<div>
  <button (click)="$event.stopPropagation(); doSomething()">Click me</button>
</div>
@Component({
  selector: 'exe-app',
  template: `
      <div>
        <button (click)="doSomething($event)">Click me</button>
      </div>`
})
export class AboutComponent {
  doSomething($event: Event) {
    $event.stopPropagation();
  }
}

在Angular框架中,我们可以自定义指令声明阻止事件冒泡

import { Directive, Output, EventEmitter, Renderer2, ElementRef } from '@angular/core';

@Directive({
    selector: '[click.stop]'
})
export class StopPropagationDirective {
    @Output("click.stop") stopPropEvent = new EventEmitter();
    unsubscribe: () => void;

    constructor(
        private renderer: Renderer2,
        private element: ElementRef) {
    }

    ngOnInit() {
        this.unsubscribe = this.renderer.listen(
            this.element.nativeElement, 'click', event => {
                event.stopPropagation();
                this.stopPropEvent.emit(event);
            });
    }

    ngOnDestroy() {
        this.unsubscribe();
    }
}

因此,在子组件中使用click事件时,只需要(click.stop)="handleClick()"则可以阻止事件的冒泡,更适合多人开发,避免了遇到一次就使用一次stopPropagation

<button (click.stop)="handleClick()">点击</button>

需要注意的是:自定义指令文件创建好后,需要在你使用到的module.ts下声明一下。

import { Directive, ElementRef, HostListener } from '@angular/core';

@Directive({
  selector: '[appMyDirective]'
})
export class MyDirectiveDirective {

  constructor(public elementRef: ElementRef) { }
  @HostListener('keyup', ['$event.target'])
  keyupFun(evt:any) {
    if (evt.value) {
      console.log(this.elementRef);
      this.elementRef.nativeElement.value = evt.value.trim();
    }
  }

}

创建好之后,在module.ts声明

import { MyDirectiveDirective } from "../../../my-directive.directive";

@NgModule({
  declarations: [
    ...
    StopPropagationDirective,
    MyDirectiveDirective
  ]
})
image.png
上一篇下一篇

猜你喜欢

热点阅读