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
相关产品推荐
相关产品推荐

