你能阻止 Angular 组件的主机点击被触发吗?

新手上路,请多包涵

我正在创建一个 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> 元素的单击事件。但是,如果您像我一样将元素放入按钮标记内,则这些目标上的单击事件会向上传播到主机。嗯,应该可以将按钮包装在另一个停止传播的元素中……

原文由 Ryan Silva 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 493
2 个回答

您可以执行以下操作:

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

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

您可以测试 此 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();
  }
}


更新

由于按钮可以包含 HTML 子元素( spanimg 等),您可以添加以下 CSS 样式以防止点击被传播到父元素:

 :host ::ng-deep button * {
  pointer-events: none;
}

感谢 @ErikWitkowski 对这个特殊案例的 评论。有关演示,请参阅 此 stackblitz

原文由 ConnorsFan 发布,翻译遵循 CC BY-SA 4.0 许可协议

我不相信有一种本机方法可以防止事件触发,正如 2016 年 这个 git 问题 所支持的那样:

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

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

原文由 Zze 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题