删除在类中定义的EventListener [英] Remove EventListener defined in a class

查看:44
本文介绍了删除在类中定义的EventListener的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试删除一个eventListener,但是好像我错过了一些事情.

下面的代码为什么不起作用,它没有从按钮中删除事件侦听器.

我也尝试将其绑定以通过范围,但这也不起作用

  class测试{eventHandler(e){console.log(e.target.id)警报()//没有效果e.target.removeEventListener("click",this.eventHandler)//也不起作用document.getElementById(e.target.id).removeEventListener("click",this.eventHandler)}Constructor(){令b = document.getElementById("b")b.addEventListener("click",this.eventHandler)//b.addEventListener("click,this.eventHandler.bind(this))}}新的Test() 

 < button id ="b">点击我</button>  

解决方案

作为事件处理程序的原型方法有点问题,特别是当您同时需要this值绑定到实例以及对实际事件处理程序函数的引用时

默认情况下,事件队列在事件绑定到的元素的上下文中调用处理程序.更改上下文很容易,但是您可以创建一个新函数,然后将其用作事件处理程序,并且该函数不再是原型中的方法.

如果要保留紧凑的类结构,一种方法是将事件处理程序方法定义为实例的自身属性,因此无法继承它们.最简单的方法是在构造函数中将方法定义为箭头函数.

  class测试{Constructor(){this.eventHandler = e =>{console.log(e.target.id);e.target.removeEventListener("click",this.eventHandler);};让b = document.getElementById("b");b.addEventListener("click",this.eventHandler);}}新的Test();  

 < button id ="b">点击我!</button>  

箭头函数保留对其定义所在的词汇环境的引用,并且事件队列不能覆盖上下文.现在,处理程序函数中的 this 已正确绑定到实例,并且 this.eventHandler 引用了附加到事件的函数.

创建自己的属性时,使用较少的内存消耗选项是使用 bind ,如下所示:

  class测试{Constructor(){this.eventHandler = this.eventHandler.bind(this);令b = document.getElementById("b");b.addEventListener("click",this.eventHandler);}eventHandler(e){console.log(e.target.id);e.target.removeEventListener("click",this.eventHandler);}} 

在此处 bind 创建一个新的函数对象,然后在原型中调用该方法,该方法的实际代码不会重复.如果您写的话,这大致相似:

  this.eventHandler = e =>Test.prototype.eventHandler.call(this,e); 

值得注意的是,当定义一个具有相同名称的基础原型属性具有的自己的属性时,prototype属性不会被覆盖,它仅被实例遮盖,并且该类的多个实例仍将按预期工作.>

另一种选择是创建自己的事件模型",该模型为所有事件创建一个包装函数(如上面的最后一个代码示例所示),并存储对该函数的引用.包装器通过 call 调用实际的处理程序,该处理程序可以将所需的 this 值绑定到事件处理程序.存储的函数引用用于删除事件.建立这样的模型并不十分复杂,但是它提供了一些有关 this 绑定和本机事件模型如何工作的知识.

I am trying to remove an eventListener but it looks like I miss something.

Why is the following code not working, it doesn't remove the event listener from the button.

I also tried binding this to pass the scope, but that didn't work either

class Test {

  eventHandler(e) {
    console.log(e.target.id)
    alert()

    // no effect
    e.target.removeEventListener("click", this.eventHandler)

    // no effect either
    document.getElementById(e.target.id).removeEventListener("click", this.eventHandler)
  }
  constructor() {
    let b = document.getElementById("b")
    b.addEventListener("click", this.eventHandler)

    //b.addEventListener("click", this.eventHandler.bind(this) )
  }
}

new Test()

<button id="b">
click me
</button>

解决方案

Prototype methods as event handlers are a bit problematic, specifically when you need both, the this value bound to the instance, and the reference to the actual event handler function.

By default, the event queue calls the handler in the context of the element the event was bound to. It's easy to change the context, but that provides you to create a new function, which then is used as the event handler, and that function is not the method in the prototype anymore.

If you want to keep the compact class structure, one way is to define the event handler methods as own properties of the instance, they simply can't be inherited. The simplest way would be to define the methods as arrow functions in the constructor.

class Test {
  constructor() {
    this.eventHandler = e => {
      console.log(e.target.id);
      e.target.removeEventListener("click", this.eventHandler);
    };
    let b = document.getElementById("b");
    b.addEventListener("click", this.eventHandler);
  }
}

new Test();

<button id="b">Click me!</button>

The arrow function keeps the reference to the lexical environment it was defined in, and the event queue can't override the context. Now this in the handler function is correctly bound to the instance, and this.eventHandler refers to the function, which was attached to the event.

A slightly less memoryconsuming option would be to use bind when creating the own property, like this:

class Test {
  constructor() {
    this.eventHandler = this.eventHandler.bind(this);
    let b = document.getElementById("b");
    b.addEventListener("click", this.eventHandler);
  }
  eventHandler (e) {
    console.log(e.target.id);
    e.target.removeEventListener("click", this.eventHandler);
  }
}

Here bind creates a new function object, which then calls the method in the prototype, the actual code of the method is not duplicated. This is loosely similar if you wrote:

this.eventHandler = e => Test.prototype.eventHandler.call(this, e);

It's notable, that when defining an own property with the same name an underlying prototype property has, the prototype property is not overridden, it's only shadowed in the instance, and multiple instances of the class will still work as intended.

Another option is to create your own "event model", which creates a wrapper function (like in the very last code example above) for all events, and stores the reference to that function. The wrapper calls the actual handler with call, which can bind the wanted this value to the event handler. The stored function references are used to remove events. Building such a model is not extremely complex, but it provides a bit knowledge of how the this binding and native event model work.

这篇关于删除在类中定义的EventListener的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆