You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中$event.stopPropagation()无法阻止父元素指令接收事件

问题:Angular自定义指令中事件阻止传播失效

场景复现

我编写了一个实现新标签页打开链接的Angular指令,原本功能正常,但将其应用在整行可点击的表格行时,单元格内的(click)事件中调用$event.stopPropagation(),却无法阻止指令触发路由跳转。对比原生routerLink的表现:第一行点击不会触发路由,但第二行使用自定义指令的会触发路由跳转。

HTML示例代码

<table>
  <tr [routerLink]="'other'">
    <td><p (click)="$event.stopPropagation()">Hello</p></td>
  </tr>
  <tr [appNewTab]="'other'">
    <td><p (click)="$event.stopPropagation()">Hello</p></td>
  </tr>
</table>
<router-outlet></router-outlet>

原指令代码

import { Directive, HostListener, Input } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';

@Directive({
  selector: '[appNewTab]',
})
export class NewTabDirective {
  @Input() appNewTab = '/';

  constructor(private router: Router, private route: ActivatedRoute) {}

  private get url(): string {
    return window.location.href + '/' + this.appNewTab;
  }

  @HostListener('mousedown', ['$event'])
  onClick($event: MouseEvent) {
    if ($event.ctrlKey || $event.metaKey || $event.button === 1) {
      window.open(this.url, '_blank');
    } else if ($event.button === 0) {
      this.router.navigate([this.appNewTab], { relativeTo: this.route });
    }
  }
}

补充说明:我尝试过使用$event.preventDefault(),也在指令的处理方法中同时调用$event.preventDefault()和$event.stopPropagation(),但都没有效果。

问题根源

指令监听的是mousedown事件,而单元格内绑定的是click事件——这两个事件是独立触发的:click事件会在鼠标释放后触发,此时单元格内的stopPropagation()无法阻止已经触发的mousedown事件后续的路由跳转逻辑。当初将监听事件从click改为mousedown,是因为原生click事件只能捕获鼠标左键点击,而我需要支持鼠标中键点击打开新标签页的场景。

解决方案

拆分HostListener为两个,分别监听click和mousedown事件,在各自的处理函数中调用stopPropagation()和preventDefault(),确保事件传播被完全阻止:

import { Directive, HostListener, Input } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';

@Directive({
  selector: '[appNewTab]',
})
export class NewTabDirective {
  @Input() appNewTab = '/';

  constructor(private router: Router, private route: ActivatedRoute) {}

  private get url(): string {
    return window.location.href + '/' + this.appNewTab;
  }

  @HostListener('click', ['$event'])
  onClick($event: MouseEvent) {
    $event.preventDefault();
    $event.stopPropagation();

    if ($event.ctrlKey || $event.metaKey) {
      window.open(this.url, '_blank');
    } else {
      this.router.navigate([this.appNewTab], { relativeTo: this.route });
    }
  }

  @HostListener('mousedown', ['$event'])
  onMouseDown($event: MouseEvent) {
    $event.preventDefault();
    $event.stopPropagation();

    if ($event.button === 1) {
      window.open(this.url, '_blank');
    }
  }
}

内容的提问来源于stack exchange,提问作者Gabriel Bergoc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 03:10:36