【问题标题】:Remove event listener vanilla JS删除事件监听器 vanilla JS
【发布时间】:2015-08-11 13:20:50
【问题描述】:

我在这支笔中尽可能简短地描述了一个特殊场景:http://codepen.io/tuelsch/pen/rVRRNm?editors=101

这篇文章 (Adding and Removing Event Listeners with parameters) 为我指明了正确的方向,但设置不同。

我喜欢有一个自定义 JS 对象 (Film),它可以在其 link 属性(一个 DOM 元素)上添加和删除事件处理程序。

我被第 18 行的 removeEvent 函数卡住了。在这种情况下,removeEventListener 函数的正确第二个参数是什么?

它没有添加和删除事件侦听器,而是不断添加事件侦听器,这可以在控制台中观察到,其中记录了第 8 行的结果。

该解决方案应该是普通的 JavaScript,兼容 ES5 并打算在浏览器 (IE9+) 中运行。

【问题讨论】:

  • 您删除一个事件侦听器,其参数与添加事件侦听器的完全相同相同

标签: javascript dom-events


【解决方案1】:
  1. 您可以先在对象中保存该绑定事件的记录,例如:
// Add the event handler
Film.prototype.bindEvent = function () {
  // This ensure that the binded event can be removed by removeEvent
  // even if you call bindEvent many times.
  if (!this._bindedEvent) {
    this._bindedEvent = this.eventHandler.bind(this);
    this.link.addEventListener('click', this._bindedEvent);
  }
}

然后删除:

// Remove the event handler
Film.prototype.removeEvent = function () {
  if (this._bindedEvent) {
    this.link.removeEventListener('click', this._bindedEvent); 
    this._bindedEvent = null;
  }
}

2 。另一种方法是在构造函数中覆盖eventhandler:

// The test class definition
var Film = function () {
  this.link = document.getElementById('film');
  // This first find if self has attr eventHandler, and keep lookup to its prototype.
  // Then createa binded version of eventhandler and set to this's attr.
  // So when you try to access `this.eventHandler`, it'll be the binded version instead of Prototype's
  this.eventHandler = this.eventHandler.bind(this);
}

那么你就可以使用

// Add the event handler
Film.prototype.bindEvent = function () {
    this.link.addEventListener('click', this.eventHandler);
}

// Remove the event handler
Film.prototype.removeEvent = function () {
    this.link.removeEventListener('click', this.eventHandler); 
}

添加和删除它。

【讨论】:

    【解决方案2】:

    当您像这里一样使用.bind(this) 时:this.link.addEventListener('click', this.eventHandler.bind(this)); 您实际上获得了一个新功能。当你尝试删除它时,你使用了原来的handler,而remove找不到绑定的handler。

    来自MDN:

    bind() 方法创建一个新函数,在调用该函数时,该函数具有 此关键字设置为提供的值,具有给定的序列 调用新函数时提供的任何参数之前的参数。

    在定义处理程序时使用绑定来修复该问题(codepen - 处理程序在 3 秒后被删除):

    // The event handler to add and remove
    Film.prototype.eventHandler = function () {
      console.log('handled');
    }.bind(Film);
    
    // Add the event handler
    Film.prototype.bindEvent = function () {
      this.link.addEventListener('click', this.eventHandler);
    }
    
    // Remove the event handler
    Film.prototype.removeEvent = function () {
      this.link.removeEventListener('click', this.eventHandler);
    }
    

    【讨论】:

    • 现在this 是窗口,不再是Film 的当前实例,在事件处理程序中需要它。
    • 感谢@phippu - 已修复。
    • 虽然我喜欢代码的简洁性,但它对我不起作用,因为在 eventHandler 内部,this 是对构造函数的引用,而不是对实例化对象的引用。
    • 构造函数的this就是实例化对象的this,因为如果不是所有实例都具有相同的属性。但是,我想知道它为什么不起作用,所以我稍后会创建一个演示,并发布它。
    猜你喜欢
    • 2017-04-16
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多