动态添加事件监听

新手上路,请多包涵

我刚刚开始使用 Angular 2,我想知道是否有人可以告诉我从元素中动态添加和删除事件侦听器的最佳方法。

我有一个组件设置。单击模板中的某个元素时,我想将 mousemove 的侦听器添加到同一模板的另一个元素。然后,我想在单击第三个元素时删除此侦听器。

我只是使用普通的 Javascript 来获取元素,然后调用标准 addEventListener() 来完成这项工作,但我想知道是否有更“ Angular2.0 ”的方式来做这件事,我应该研究一下。

原文由 popClingwrap 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

渲染器在 Angular 4.0.0-rc.1 中已被弃用,请阅读下面的更新

angular2 方法 是使用来自 渲染器listenlistenGlobal

例如,如果您想向组件添加点击事件,则必须使用 Renderer 和 ElementRef(这也为您提供了使用 ViewChild 或任何检索 nativeElement 的选项)

 constructor(elementRef: ElementRef, renderer: Renderer) {

    // Listen to click events in the component
    renderer.listen(elementRef.nativeElement, 'click', (event) => {
      // Do something with 'event'
    })
);

您可以使用 listenGlobal 这将使您可以访问 documentbody 等。

 renderer.listenGlobal('document', 'click', (event) => {
  // Do something with 'event'
});

请注意,由于 listenlistenGlobal 返回一个函数来删除监听器(参见 beta.2 的 变更 日志中的重大更改部分)。这是为了避免大型应用程序中的内存泄漏(请参阅 #6686 )。

因此,要删除我们动态添加的侦听器,我们必须将 listenlistenGlobal 分配给将保存返回函数的变量,然后我们执行它。

 // listenFunc will hold the function returned by "renderer.listen"
listenFunc: Function;

// globalListenFunc will hold the function returned by "renderer.listenGlobal"
globalListenFunc: Function;

constructor(elementRef: ElementRef, renderer: Renderer) {

    // We cache the function "listen" returns
    this.listenFunc = renderer.listen(elementRef.nativeElement, 'click', (event) => {
        // Do something with 'event'
    });

    // We cache the function "listenGlobal" returns
    this.globalListenFunc = renderer.listenGlobal('document', 'click', (event) => {
        // Do something with 'event'
    });
}

ngOnDestroy() {
    // We execute both functions to remove the respectives listeners

    // Removes "listen" listener
    this.listenFunc();

    // Removs "listenGlobal" listener
    this.globalListenFunc();
}

这是一个带有示例工作的 plnkr 。该示例包含 listenlistenGlobal 的用法。

将 RendererV2 与 Angular 4.0.0-rc.1+ 一起使用(从 4.0.0-rc.3 开始的 Renderer2)

  • 25/02/2017 : Renderer 已被弃用,现在我们应该使用RendererV2 (见下一行)。查看 提交

  • 10/03/2017 : RendererV2 更名为 Renderer2 。查看 重大变化

RendererV2 不再有 listenGlobal 全局事件(文档、正文、窗口)函数。它只有一个实现这两个功能的 listen 函数。

作为参考,我复制并粘贴了 DOM Renderer 实现的 源代码,因为它可能会改变(是的,它是有角度的!)。

 listen(target: 'window'|'document'|'body'|any, event: string, callback: (event: any) => boolean):
      () => void {
    if (typeof target === 'string') {
      return <() => void>this.eventManager.addGlobalEventListener(
          target, event, decoratePreventDefault(callback));
    }
    return <() => void>this.eventManager.addEventListener(
               target, event, decoratePreventDefault(callback)) as() => void;
  }

如您所见,现在它验证我们是否正在传递一个字符串(文档、正文或窗口),在这种情况下,它将使用内部 addGlobalEventListener 函数。在任何其他情况下,当我们传递一个元素(nativeElement)时,它将使用一个简单的 addEventListener

要删除监听器,它与 Renderer 在 angular 2.x 中相同。 listen 返回一个函数,然后调用该函数。

例子

// Add listeners
let global = this.renderer.listen('document', 'click', (evt) => {
  console.log('Clicking the document', evt);
})

let simple = this.renderer.listen(this.myButton.nativeElement, 'click', (evt) => {
  console.log('Clicking the button', evt);
});

// Remove listeners
global();
simple();

plnkrAngular 4.0.0-rc.1 使用 RendererV2

plnkrAngular 4.0.0-rc.3 使用 Renderer2

原文由 Eric Martinez 发布,翻译遵循 CC BY-SA 4.0 许可协议

我将添加一个 StackBlitz 示例 和对@tahiche 答案的评论。

返回值是一个函数,用于在添加事件侦听器后删除它。当您不再需要事件侦听器时,删除它们被认为是一种很好的做法。所以你可以存储这个返回值并在你的 ngOnDestroy 方法中调用它。

我承认一开始它可能看起来令人困惑,但它实际上是一个非常有用的功能。你还能怎么清理自己?

 export class MyComponent implements OnInit, OnDestroy {

  public removeEventListener: () => void;

  constructor(
    private renderer: Renderer2,
    private elementRef: ElementRef
  ) {
  }

  public ngOnInit() {
    this.removeEventListener = this.renderer.listen(this.elementRef.nativeElement, 'click', (event) => {
      if (event.target instanceof HTMLAnchorElement) {
        // Prevent opening anchors the default way
        event.preventDefault();
        // Your custom anchor click event handler
        this.handleAnchorClick(event);
      }
    });
  }

  public ngOnDestroy() {
    this.removeEventListener();
  }
}

你可以 在这里找到一个 StackBlitz 来展示它是如何捕捉点击锚元素的。

我添加了一个带有图像的主体,如下所示:

<img src="x" onerror="alert(1)"></div>

以表明消毒剂正在发挥作用。

在这个小提琴中,您会发现与 innerHTML 相同的主体没有对其进行消毒,它将证明该问题。

原文由 Wilt 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进