你可以阻止Angular组件的主机点击发射吗?

时间:2018-03-21 20:11:42

标签: javascript angular angular-template

我正在创建一个Angular组件,它包含一个带有一些附加功能的原生<button>元素。如果它们被禁用并且我想要复制相同的功能,则按钮不会触发单击事件。即,给定:

<my-button (click)="onClick()" [isDisabled]="true">Save</my-button>

my-button是否有办法阻止调用onClick()

在Angular中,您可以通过这种方式收听主机点击事件,并停止事件的传播

//Inside my-button component
@HostListener('click', ['$event'])
onHostClick(event: MouseEvent) {
  event.stopPropagation();
}

这可以防止事件冒泡到祖先元素,但它不会阻止内置(click)输出在同一主机元素上触发。

有没有办法实现这个目标?

编辑1:我现在解决这个问题的方法是使用名为“onClick”的不同输出,消费者必须知道使用“onClick”而不是“click”。这不太理想。

编辑2 :成功停止了源自<button>元素的点击事件。但是如果你像我一样将元素放在按钮标记内,那么单击这些目标上的事件会传播到主机。嗯,应该可以将按钮包裹在另一个停止传播的元素中......

3 个答案:

答案 0 :(得分:5)

您可以执行以下操作:

  • 重新定义组件的click事件,并在单击按钮时发出此事件
  • 在组件主机上设置CSS样式pointer-events: none
  • 在按钮上设置CSS样式pointer-events: auto
  • 在按钮点击事件处理程序
  • 上调用event.stopPropagation()

如果您需要处理组件内其他元素的click事件,请在其上设置样式属性pointer-events: auto,并在其Click事件处理程序中调用event.stopPropagation()

您可以在this stackblitz中测试代码。

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

@Component({
  selector: 'my-button',
  host: {
    "[style.pointer-events]": "'none'"
  },
  template: `
    <button (click)="onButtonClick($event)" [disabled]="isDisabled" >...</button>
    <span (click)="onSpanClick($event)">Span element</span>`,
  styles: [`button, span { pointer-events: auto; }`]
})
export class MyCustomComponent {

  @Input() public isDisabled: boolean = false;
  @Output() public click: EventEmitter<MouseEvent> = new EventEmitter();

  onButtonClick(event: MouseEvent) {
    event.stopPropagation();
    this.click.emit(event);
  }

  onSpanClick(event: MouseEvent) {
    event.stopPropagation();
  }
}

答案 1 :(得分:1)

我不相信有一种本地方法可以防止事件被解雇,正如2016年this git issue所支持的那样:

  

执行顺序是红色鲱鱼 - 当前未定义同一元素上的事件传播到多个侦听器的顺序。这是目前的设计。

     

您的问题是暴露给侦听器的事件是真正的DOM事件,并且在提供的事件上调用stopImmediatePropagation()会停止执行在此元素上注册的其他侦听器。 但是,由于通过Angular注册的所有侦听器仅由一个dom侦听器代理(出于性能原因),对此事件调用stopImmediatePropagation无效。

答案 2 :(得分:0)

您可以使用本机添加和删除EventListeners。从角度来看,这绝不是一个好的解决方案。此外,如果您将disabled属性放在button中,因为它将覆盖附加的eventListeners,这将无法工作。需要使用disabled类。 (或者将button包裹在span中并使用模板引用#btn。)

StackBlitz

import { Component, OnInit, OnChanges, HostListener, Input, Output, EventEmitter, SimpleChanges, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-my-button',
  template: `<button [class.disabled]="isDisabled" #btn><span>hey</span></button>`,
  styles: [`button.disabled { opacity:0.5 }`]
})
export class MyButtonComponent implements OnInit, OnChanges {
  disableClick = e => e.stopPropagation();
  @Input() isDisabled: boolean;
  @ViewChild('btn') btn: ElementRef;
  constructor() { }

  ngOnChanges(changes: SimpleChanges) {
    if(this.isDisabled) {
      this.btn.nativeElement.addEventListener('click', this.disableClick);
    } else {
      this.btn.nativeElement.removeEventListener('click', this.disableClick);
    }
  }
  ngOnInit() {
  }

}