Clarity clr-icon绑定@HostListener点击事件不触发如何解决?
问题原因排查
- 第一个错误:
@HostListener装饰器位置错误,你当前将它写在了类定义外部,不属于ControlDeleteDirective类的成员,自然不会生效 - 第二个错误:
setupDeleteIcon中仅定义了clr-icon的模板字符串,没有实际插入到宿主DOM中,且模板字符串里的(click)是Angular模板语法,直接以普通字符串插入DOM时Angular不会解析该事件绑定,点击事件不会触发 - 全局监听方案的问题:你绑定的是全局document点击事件,每次页面任意位置点击都会触发逻辑,且你没有判断被点击的clr-icon是否属于当前指令生成的元素,会导致所有页面上的clr-icon点击都会触发你的事件发射器,你所说的「自动调用」大概率是事件冒泡或其他位置的点击命中了判断逻辑
可行实现方案
推荐直接用Renderer2动态创建元素并绑定事件,不需要全局监听,逻辑更安全:
import { Directive, Output, EventEmitter, AfterViewInit, OnDestroy, ElementRef, Renderer2 } from '@angular/core'; @Directive({ selector: '[deleteIcon]' }) export class ControlDeleteDirective implements AfterViewInit, OnDestroy { @Output() delete: EventEmitter<boolean> = new EventEmitter<boolean>(); // 存储生成的clr-icon元素,用于销毁时清理 private deleteIconElement: HTMLElement | null = null; // 存储点击事件解绑函数,用于销毁时清理 private clickUnlistener: (() => void) | null = null; constructor( // 获取指令挂载的宿主元素 private hostEl: ElementRef, private renderer: Renderer2 ) {} ngAfterViewInit () { this.setupDeleteIcon(); } ngOnDestroy() { // 销毁时清理事件和元素,避免内存泄漏 if (this.clickUnlistener) { this.clickUnlistener(); } if (this.deleteIconElement && this.hostEl.nativeElement.contains(this.deleteIconElement)) { this.renderer.removeChild(this.hostEl.nativeElement, this.deleteIconElement); } } private setupDeleteIcon() { // 用Renderer2创建clr-icon元素 this.deleteIconElement = this.renderer.createElement('clr-icon'); // 设置属性 this.renderer.setAttribute(this.deleteIconElement, 'shape', 'times-circle'); this.renderer.setAttribute(this.deleteIconElement, 'class', 'is-solid'); this.renderer.setStyle(this.deleteIconElement, 'color', '#0076CE'); this.renderer.setStyle(this.deleteIconElement, 'cursor', 'pointer'); // 绑定点击事件,拿到解绑函数 this.clickUnlistener = this.renderer.listen(this.deleteIconElement, 'click', () => { this.delete.next(true); }); // 将生成的图标插入到宿主元素中 this.renderer.appendChild(this.hostEl.nativeElement, this.deleteIconElement); } }
补充说明
如果确实需要用@HostListener的方案,也可以修正位置后监听宿主元素的点击,然后判断点击目标是否是你生成的图标:
@Directive({ selector: '[deleteIcon]' }) export class ControlDeleteDirective implements AfterViewInit, OnDestroy { @Output() delete: EventEmitter<boolean> = new EventEmitter<boolean>(); private deleteIconElement: HTMLElement | null = null; constructor(private hostEl: ElementRef, private renderer: Renderer2) {} // 放在类内部,监听宿主元素的点击事件 @HostListener('click', ['$event']) onClick(event: MouseEvent){ // 判断点击目标是不是你生成的那个clr-icon if (this.deleteIconElement && event.target === this.deleteIconElement) { this.delete.next(true); } } // setupDeleteIcon逻辑和上面一致,插入元素即可,不需要手动绑定点击事件 // 其余生命周期函数同上 }
内容的提问来源于stack exchange,提问作者user21
相关产品推荐
相关产品推荐

