删除通过绑定添加的事件侦听器

IT技术 javascript events listener bind
2021-01-26 19:27:54

在 JavaScript 中,使用 bind() 删除作为事件侦听器添加的函数的最佳方法是什么?

例子

(function(){

    // constructor
    MyClass = function() {
        this.myButton = document.getElementById("myButtonID");
        this.myButton.addEventListener("click", this.clickListener.bind(this));
    };

    MyClass.prototype.clickListener = function(event) {
        console.log(this); // must be MyClass
    };

    // public method
    MyClass.prototype.disableButton = function() {
        this.myButton.removeEventListener("click", ___________);
    };

})();

我能想到的唯一方法是跟踪每个添加了 bind 的监听器。

上面这个方法的例子:

(function(){

    // constructor
    MyClass = function() {
        this.myButton = document.getElementById("myButtonID");
        this.clickListenerBind = this.clickListener.bind(this);
        this.myButton.addEventListener("click", this.clickListenerBind);
    };

    MyClass.prototype.clickListener = function(event) {
        console.log(this); // must be MyClass
    };

    // public method
    MyClass.prototype.disableButton = function() {
        this.myButton.removeEventListener("click", this.clickListenerBind);
    };

})();

有没有更好的方法来做到这一点?

6个回答

尽管@machineghost 所说的是正确的,但事件的添加和删除方式相同,但等式中缺失的部分是:

.bind()调用创建一个新的函数引用

请参阅bind() 是否更改函数引用?| 如何永久设置?

因此,要添加或删除它,请将引用分配给变量:

var x = this.myListener.bind(this);
Toolbox.addListener(window, 'scroll', x);
Toolbox.removeListener(window, 'scroll', x);

这对我来说按预期工作。

这与问题中提到的方法没有什么不同(也不比)。
2021-03-29 19:27:54
@AlbertoAcuña 现代浏览器使用.addEventListener(type, listener).removeEventListener(type, listener)来添加和删除元素上的事件。对于两者,您都可以将解决方案中描述的函数引用作为listener参数传递"click"作为类型。developer.mozilla.org/en-US/docs/Web/API/EventTarget/...
2021-03-30 19:27:54
这对我有帮助——尽管这个答案是 4 年前发布的 :)
2021-04-02 19:27:54
太好了,这应该是公认的答案。感谢您更新一个旧主题,这个主题在搜索引擎上排名第一,直到您现在发布它为止,它没有适当的解决方案。
2021-04-04 19:27:54
我不明白,你如何让它与点击事件一起工作,谢谢
2021-04-04 19:27:54

对于那些在向/从 Flux 商店注册/删除 React 组件的侦听器时遇到此问题的人,请将以下行添加到您的组件的构造函数中:

class App extends React.Component {
  constructor(props){
    super(props);
    // it's a trick! needed in order to overcome the remove event listener
    this.onChange = this.onChange.bind(this);  
  }
  // then as regular...
  componentDidMount (){
    AppStore.addChangeListener(this.onChange);
  }
  
  componentWillUnmount (){
    AppStore.removeChangeListener(this.onChange);
  }

  onChange () {
    let state = AppStore.getState();
    this.setState(state);
  }
  
  render() {
    // ...
  }
  
}

从不同的类或原型函数中添加和删除事件侦听器时,这似乎是正确的方法,我相信与此的联系也适用于 React 组件/类。您将它绑定在一个公共(例如,根)实例级别。
2021-03-22 19:27:54
不错的技巧,但是 React/Flux 有什么关系呢?
2021-03-27 19:27:54
this.onChange = this.onChange.bind(this)其实这就是我要找的。this永远绑定的功能:)
2021-04-02 19:27:54

是否使用绑定函数并不重要;您可以像删除任何其他事件处理程序一样删除它。如果您的问题是绑定版本是它自己的唯一函数,您可以跟踪绑定版本,或者使用removeEventListener不采用特定处理程序签名(当然,这将删除相同类型的其他事件处理程序)。

(附带说明,addEventListener并非在所有浏览器中都有效;您确实应该使用像 jQuery 这样的库以跨浏览器的方式为您进行事件连接。此外,jQuery 具有命名空间事件的概念,它允许您绑定到“click.foo”;当您想删除事件时,您可以告诉 jQuery“删除所有 foo 事件”,而无需知道特定的处理程序或删除其他处理程序。)

那会是哪个签名? removeEventListener 上的 MDN 页面显示前两个参数都是必需的。
2021-03-24 19:27:54
我的错。我写这个答案已经好几年了,但我一定一直在考虑 jQueryoffunbind方法。要删除元素上的所有侦听器,您必须在添加它们时对其进行跟踪(这是 jQuery 或其他库可以为您做的事情)。
2021-03-25 19:27:54
我知道 IE 问题。我正在开发一个严重依赖画布的应用程序,所以 IE7- 已经过时了。IE8 至少支持画布。IE9+ 支持 addEventListener。jQuery 的命名空间事件看起来非常整洁。我唯一担心的是效率。
2021-04-04 19:27:54
JQuery 命名空间事件被广泛使用并且几乎没有性能问题。告诉某人不要使用可以使他们的代码更容易和(可以说更重要)更容易理解的工具,这将是一个可怕的建议,特别是如果这样做是出于对 JQuery 的非理性恐惧和想象中的性能问题。
2021-04-06 19:27:54
jQuery 人员非常努力地保持他们的库运行良好,所以我不会太担心。但是,考虑到您对浏览器的严格要求,您可能想改用 Zepto。它有点像 jQuery 的缩小版本,速度更快但不能支持旧浏览器(并且有一些其他限制)。
2021-04-11 19:27:54

jQuery 解决方案:

let object = new ClassName();
let $elem = $('selector');

$elem.on('click', $.proxy(object.method, object));

$elem.off('click', $.proxy(object.method, object));

我们在无法更改的库中遇到了这个问题。Office Fabric UI,这意味着我们无法更改添加事件处理程序的方式。我们解决它的方法是覆盖原型addEventListener上的EventTarget

这将在对象上添加一个新函数 element.removeAllEventListers("click")

(原帖:从结构对话框覆盖中删除点击处理程序

        <script>
            (function () {
                "use strict";

                var f = EventTarget.prototype.addEventListener;

                EventTarget.prototype.addEventListener = function (type, fn, capture) {
                    this.f = f;
                    this._eventHandlers = this._eventHandlers || {};
                    this._eventHandlers[type] = this._eventHandlers[type] || [];
                    this._eventHandlers[type].push([fn, capture]);
                    this.f(type, fn, capture);
                }

                EventTarget.prototype.removeAllEventListeners = function (type) {
                    this._eventHandlers = this._eventHandlers || {};
                    if (type in this._eventHandlers) {
                        var eventHandlers = this._eventHandlers[type];
                        for (var i = eventHandlers.length; i--;) {
                            var handler = eventHandlers[i];
                            this.removeEventListener(type, handler[0], handler[1]);
                        }
                    }
                }

                EventTarget.prototype.getAllEventListeners = function (type) {
                    this._eventHandlers = this._eventHandlers || {};
                    this._eventHandlers[type] = this._eventHandlers[type] || [];
                    return this._eventHandlers[type];
                }

            })();
        </script>