Angular中event.stopPropagation()为何无法阻止父指令@HostListener接收点击事件?
问题分析
原生<button>元素处于禁用状态时,浏览器不会触发它的click事件,这意味着你在组件内部<button>上绑定的onClick方法根本不会执行,event.stopImmediatePropagation()自然也无法生效。
而你将throttledClick指令绑定在<app-button>组件本身上,指令的HostListener监听的是组件宿主元素的click事件。当点击禁用按钮的区域时,事件会冒泡到<app-button>宿主元素,触发指令的handleClick方法,导致节流逻辑被意外执行。
解决方案
下面提供几种可行的解决方式:
方案一:将节流指令绑定到内部原生按钮
直接把节流指令移到组件内部的<button>元素上,利用原生禁用按钮不触发click事件的特性,从根源上阻止节流逻辑执行:
修改ButtonComponent的模板和逻辑:
import { Component, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-button', template: ` <button [disabled]="isDisabled" throttledClick (throttledClick)="onClick($event)"> <ng-content></ng-content> </button> `, }) export class ButtonComponent { @Input() isDisabled = false; @Output() click = new EventEmitter<Event>(); onClick(event: Event) { this.click.emit(event); } }
使用组件时,直接绑定组件的click输出:
<app-button [isDisabled]="isButtonDisabled" (click)="onThrottledClick()"> Click Me </app-button>
方案二:让指令感知按钮的禁用状态
通过依赖注入让节流指令获取<app-button>组件的实例,在触发节流逻辑前先检查按钮是否禁用:
修改ThrottledClickDirective:
import { Directive, Output, EventEmitter, HostListener, Inject, Optional } from '@angular/core'; import { ButtonComponent } from './button.component'; @Directive({ selector: '[throttledClick]', }) export class ThrottledClickDirective { @Output() throttledClick = new EventEmitter<Event>(); private isThrottled = false; constructor(@Optional() @Inject(ButtonComponent) private buttonComp?: ButtonComponent) {} @HostListener('click', ['$event']) handleClick(event: Event) { // 如果绑定在app-button上,先判断按钮是否禁用 if (this.buttonComp?.isDisabled) { return; } if (!this.isThrottled) { this.isThrottled = true; this.throttledClick.emit(event); setTimeout(() => this.isThrottled = false, 200); } } }
方案三:阻止宿主元素接收点击事件
在组件宿主元素上添加pointer-events: none样式,当按钮禁用时,直接阻止点击事件触发到宿主元素:
修改ButtonComponent:
import { Component, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-button', template: ` <button [disabled]="isDisabled" (click)="onClick($event)"> <ng-content></ng-content> </button> `, host: { '[class.disabled]': 'isDisabled' } }) export class ButtonComponent { @Input() isDisabled = false; @Output() click = new EventEmitter<Event>(); onClick(event: Event) { if (!this.isDisabled) { this.click.emit(event); } } }
添加对应的CSS样式:
app-button.disabled { pointer-events: none; opacity: 0.6; cursor: not-allowed; }
内容的提问来源于stack exchange,提问作者Rahul Raj
相关产品推荐
相关产品推荐

