正在删除使用绑定添加的事件侦听器
Removing event listener which was added with 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", ___________);
};
})();
我能想到的唯一方法就是跟踪每一个添加了绑定的侦听器。
上面这个方法的例子:
(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);
};
})();
有更好的方法吗?
尽管@machineghost所说的是真的,事件的添加和删除方式相同,但等式中缺少的部分是:
在调用
.bind()
之后,将创建一个新的函数引用。
请参阅bind()是否更改函数引用?|如何永久设置?
因此,要添加或删除它,请将引用分配给一个变量:
var x = this.myListener.bind(this);
Toolbox.addListener(window, 'scroll', x);
Toolbox.removeListener(window, 'scroll', x);
这对我来说是意料之中的事。
对于那些在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() {
// ...
}
}
是否使用绑定函数并不重要;删除它的方式与删除任何其他事件处理程序的方式相同。如果您的问题是绑定版本是它自己的唯一函数,那么您可以跟踪绑定版本,也可以使用不使用特定处理程序的removeEventListener
签名(当然,这会删除相同类型的其他事件处理程序)。
(顺便说一句,addEventListener
并不是在所有浏览器中都能工作;你真的应该使用像jQuery这样的库来以跨浏览器的方式为你进行事件连接。此外,jQuery有名称空间事件的概念,它允许你绑定到"click.foo";当你想删除事件时,你可以告诉jQuery"删除所有foo事件"而不必知道特定的处理程序或移除其他处理程序。)
let object = new ClassName();
let $elem = $('selector');
$elem.on('click', $.proxy(object.method, object));
$elem.off('click', $.proxy(object.method, object));
我们遇到了无法更改的库问题。Office Fabric UI,这意味着我们无法更改添加事件处理程序的方式。我们解决这个问题的方法是在EventTarget
原型上重写addEventListener
。
这将在对象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>
以下是解决方案:
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);
正如其他人所说,bind
创建了一个新的函数实例,因此除非以某种方式记录,否则无法删除事件侦听器。
为了获得更漂亮的代码样式,您可以将方法函数设置为惰性getter,以便在第一次访问时自动替换为绑定版本:
class MyClass {
activate() {
window.addEventListener('click', this.onClick);
}
deactivate() {
window.removeEventListener('click', this.onClick);
}
get onClick() {
const func = (event) => {
console.log('click', event, this);
};
Object.defineProperty(this, 'onClick', {value: func});
return func;
}
}
如果不支持ES6箭头功能,请使用const func = (function(event){...}).bind(this)
而不是const func = (event) => {...}
。
Raichman Sergey的方法也很好,尤其是在课堂上。这种方法的优点是它更自完整,并且除了where之外没有分离的代码。它也适用于没有构造函数或启动器的对象。
如果你想使用如上所述的"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 = "";
};
})();
我希望它能有所帮助。
可以使用关于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() {
// ...
}
}
这已经有一段时间了,但MDN对此有一个超级解释。这对我的帮助比这里的东西还大。
MDN::EventTarget.addEventListener-处理程序中"this"的值
它为handleEvent函数提供了一个很好的替代方案。
这是一个有绑定和无绑定的例子:
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的特殊函数来捕获任何事件:
- 如何在for循环中添加事件侦听器
- 如果选中了多个复选框,如何添加事件
- 正在ng重复元素上添加事件
- 在动态创建的标记上添加事件
- 如何在HTML列表中添加事件's子弹
- 将事件侦听器添加到文档,而不是签入元素存在,然后添加事件侦听器
- jQuery完整日历添加事件,仅包含月份和日期
- 是否可以在数字输入框中的小按钮中添加事件侦听器
- 在Google Chrome扩展中添加事件侦听器
- AngularJS:在.post()之后添加事件侦听器
- 对象 Javascript 中的标签无效 - 想要添加事件列表器
- 添加事件侦听器不起作用
- 如何为angular js条形图添加事件
- 在 http 请求中添加事件侦听器 ( request.on ) 是什么意思?而笏就是它的用途
- Iron:路由器在更改路由器上添加事件
- 如何为表行结果的每个按钮添加事件侦听器
- 在 javascript 中添加事件处理程序的位置
- YouTube API-动态添加事件侦听器
- 在聚合物的子菜单标题中添加事件
- 检查是否可以添加事件侦听器而不添加