在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);
};
})();
有没有更好的方法来做到这一点?
答案 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的特殊函数来捕获任何事件: