删除使用bind添加的事件侦听器

时间:2012-07-19 16:42:55

标签: javascript events listener bind

在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);
    };

})();

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

9 个答案:

答案 0 :(得分:233)

虽然@machineghost说的是真的,但事件的添加和删除方式相同,方程式的缺失部分是:

  

在调用.bind()后创建新的函数引用!

请参阅Does bind() change the function reference? | How to set permanently?

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

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

这对我有用。

答案 1 :(得分:40)

对于那些在向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() {
    // ...
  }
  
}

答案 2 :(得分:3)

是否使用绑定功能无关紧要;您以与任何其他事件处理程序相同的方式删除它。如果您的问题是绑定版本是它自己的唯一函数,您可以跟踪绑定版本,或使用不带特定处理程序的removeEventListener签名(当然,这将删除其他事件相同类型的处理程序)。

(作为旁注,addEventListener在所有浏览器中都不起作用;你真的应该使用像jQuery这样的库来以跨浏览器的方式为你做事件连接。此外,jQuery还有命名空间事件的概念,它允许你绑定到“click.foo”;当你想要删除事件时,你可以告诉jQuery“删除所有的foo事件”而不必知道特定的处理程序或删除其他处理程序。)

答案 3 :(得分:1)

jQuery解决方案:

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

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

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

答案 4 :(得分:0)

以下是解决方案:

var o = {
  list: [1, 2, 3, 4],
  add: function () {
    var b = document.getElementsByTagName('body')[0];
    b.addEventListener('click', this._onClick());

  },
  remove: function () {
    var b = document.getElementsByTagName('body')[0];
    b.removeEventListener('click', this._onClick());
  },
  _onClick: function () {
    this.clickFn = this.clickFn || this._showLog.bind(this);
    return this.clickFn;
  },
  _showLog: function (e) {
    console.log('click', this.list, e);
  }
};


// Example to test the solution
o.add();

setTimeout(function () {
  console.log('setTimeout');
  o.remove();
}, 5000);

答案 5 :(得分:0)

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

这将在对象element.removeAllEventListers("click")上添加新功能

(原始帖子:Remove Click handler from fabric dialog overlay

        <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>

答案 6 :(得分:0)

可以使用大约ES7:

class App extends React.Component {
  constructor(props){
    super(props);
  }
  componentDidMount (){
    AppStore.addChangeListener(this.onChange);
  }

  componentWillUnmount (){
    AppStore.removeChangeListener(this.onChange);
  }

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

  render() {
    // ...
  }

}

答案 7 :(得分:-1)

如果你想使用'onclick',如上所述,你可以试试这个:

(function(){
    var singleton = {};

    singleton = new function() {
        this.myButton = document.getElementById("myButtonID");

        this.myButton.onclick = function() {
            singleton.clickListener();
        };
    }

    singleton.clickListener = function() {
        console.log(this); // I also know who I am
    };

    // public function
    singleton.disableButton = function() {
        this.myButton.onclick = "";
    };
})();

我希望它有所帮助。

答案 8 :(得分:-2)

已经过了一段时间,但MDN对此有一个很好的解释。这比这里的东西更有帮助。

MDN :: EventTarget.addEventListener - The value of "this" within the handler

它为handleEvent函数提供了一个很好的替代方法。

这是一个带有和不带bind的例子:

var Something = function(element) {
  this.name = 'Something Good';
  this.onclick1 = function(event) {
    console.log(this.name); // undefined, as this is the element
  };
  this.onclick2 = function(event) {
    console.log(this.name); // 'Something Good', as this is the binded Something object
  };
  element.addEventListener('click', this.onclick1, false);
  element.addEventListener('click', this.onclick2.bind(this), false); // Trick
}

上面示例中的一个问题是您无法使用bind删除侦听器。另一个解决方案是使用一个名为handleEvent的特殊函数来捕获任何事件: