如何在 Angular 2 中为已呈现的元素绑定事件监听器?

73

我该如何在Angular 2中绑定渲染元素的事件监听器?

我正在使用 Dragula 拖放库。它创建动态 HTML,但我的事件未绑定到动态HTML元素。


什么是“渲染元素”或“动态HTML元素”。请添加演示您要完成的代码。 - Günter Zöchbauer
8个回答

145
import { AfterViewInit, Component, ElementRef} from '@angular/core';

constructor(private elementRef:ElementRef) {}

ngAfterViewInit() {
  this.elementRef.nativeElement.querySelector('my-element')
                                .addEventListener('click', this.onClick.bind(this));
}

onClick(event) {
  console.log(event);
}

11
在销毁组件后是否需要任何手动清除 (.removeEventListener()),还是 Angular 会自行处理? - kraftwer1
4
不,如果你强制注册它,你需要强制删除它。 - Günter Zöchbauer
2
@Kannan 当你传递给 bind 的内容在 onClick() { ... } 被调用时将作为 this 可用,因此基本上可以传递任何对象。 - Günter Zöchbauer
4
这虽然是一个小细节,但可能会让一些人感到困惑。选择器开头必须加上 # 或 .,具体取决于它是否为 ID 或类名,例如如果 <div id="my-element">,则应该写成 '#my-element' - Mike Poole
4
请在类声明中添加 implements AfterViewInit - tblev
显示剩余9条评论

45
为了在angular 2+中向元素添加EventListener,我们可以使用Renderer2服务的listen方法(Renderer已弃用,请使用Renderer2):

listen(target: 'window'|'document'|'body'|any, eventName: string, callback: (event: any) => boolean | void): () => void

例子:
export class ListenDemo implements AfterViewInit { 
   @ViewChild('testElement') 
   private testElement: ElementRef;
   globalInstance: any;       

   constructor(private renderer: Renderer2) {
   }

   ngAfterViewInit() {
       this.globalInstance = this.renderer.listen(this.testElement.nativeElement, 'click', () => {
           this.renderer.setStyle(this.testElement.nativeElement, 'color', 'green');
       });
    }
}

注意:

当您使用此方法向dom元素添加事件监听器时,应在组件被销毁时删除此事件监听器

您可以这样做:

ngOnDestroy() {
  this.globalInstance();
}

在这种方法中使用ElementRef的方式不应该让你的Angular应用程序面临安全风险。了解更多信息,请参考ElementRef security risk angular 2


4
需要在 onDestroy 中进行 "取消订阅(un-listen)" 吗?还是 Angular 会自行处理? - Wolf359
4
@MehmetGunacti: 很好的问题。答案是是的,当ngOnDestroy被调用时,你应该取消监听。我会更新答案并提供一个参考,像这样使用this.renderer.listenglobalInstance=this.renderer.listen ... 然后在ngOnDestroy()中调用它:{this.globalInstance();} - HDJEMAI
@HDJEMAI 我非常喜欢这个答案,但是我们如何将 #testElement 添加到渲染的元素中,而该元素不在我们的控制范围内? - stack247

20

HostListener 应该是将事件绑定到组件的适当方式:

@Component({
  selector: 'your-element'
})

export class YourElement {
  @HostListener('click', ['$event']) onClick(event) {
     console.log('component is clicked');
     console.log(event);
  }
}

8

如果您想为渲染的DOM元素中具有相同类的所有元素绑定像“click”这样的事件,则可以使用components.ts文件中以下代码部分设置事件监听器。

import { Component, OnInit, Renderer, ElementRef} from '@angular/core';

constructor( elementRef: ElementRef, renderer: Renderer) {
    dragulaService.drop.subscribe((value) => {
      this.onDrop(value.slice(1));
    });
}

public onDrop(args) {

  let [e, el] = args;

  this.toggleClassComTitle(e,'checked');

}


public toggleClassComTitle(el: any, name: string) {

    el.querySelectorAll('.com-item-title-anchor').forEach( function ( item ) {

      item.addEventListener('click', function(event) {
              console.log("item-clicked");

       });
    });

}

6
@HostListener('window:click', ['$event']) onClick(event){ }

请检查下面的链接,可以在当前窗口的单击、松开和按下键盘时检测大写锁定状态。无需在HTML文档中添加任何事件。

Detect and warn users about caps lock is on


0

这个例子将帮助您添加事件监听器和与触摸相关的滑动手势。

import { Component, HostListener, Input, OnInit } from '@angular/core';
  
export class AppbarComponent implements OnInit {
  
    touchstartX:number = 0;
    touchstartY:number = 0;
    touchendX:number = 0;
    touchendY:number = 0;

    @HostListener('touchstart', ['$event']) gesuredZonestart(event:any) {
      this.touchstartX = event.changedTouches[0].screenX;
      this.touchstartY = event.changedTouches[0].screenY;  
    }
    
    @HostListener('touchend', ['$event']) gesuredZoneend(event:any) {
      this.touchendX = event.changedTouches[0].screenX;
      this.touchendY = event.changedTouches[0].screenY; 
      this.handleGesure(); 
    }

    handleGesure() {
      var swiped = 'swiped: ';
      if (this.touchendX < this.touchstartX) {
          console.log(swiped + 'left!');
      }
      if (this.touchendX > this.touchstartX) {
          console.log(swiped + 'right!');
      }
      if (this.touchendY < this.touchstartY) {
          console.log(swiped + 'down!'); 
      }
      if (this.touchendY > this.touchstartY) {
          console.log(swiped + 'top!');
      }
      if (this.touchendY == this.touchstartY) {
          console.log('tap!');
      }
    }
}


0
import { Component, OnInit } from '@angular/core';

在组件内创建变量:

onlineStatus: any; 

在 ngOnInit() 生命周期方法中,您可以编写任何您喜欢的内容,并且它将被视为普通的 JS 画布。
  ngOnInit(): void {
    const updateNetworkStatus = () => {
      const text = window.navigator.onLine ? ' online' : ' offline'
      this.onlineStatus = text
    }
    
    updateNetworkStatus()
    window.addEventListener('offline', updateNetworkStatus)
    window.addEventListener('online', updateNetworkStatus)
  }

我在我的YouTube频道上制作了一段关于如何做到这一点的视频

0

有一种很好的方法可以检测Angular中的子元素何时被渲染并访问它。

我在Stack Overflow上找到了这个方法,但不记得在哪里了。

  private myElement: ElementRef;
  @ViewChild('mySelector', {static : false}) set content(content: ElementRef) {
    if(content) { // initially setter gets called with undefined
      // debugger;
      this.myElement = content;
    }
  }


<div #mySelector *ngIf="initiallyFalseThenAfterDbResponseIsTrue"></div>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接