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);
これは期待どおりに機能します。
ReactコンポーネントのリスナーをFluxストアに登録/削除する際にこの問題がある場合は、コンポーネントのコンストラクターに以下の行を追加してください。
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イベントを削除」することができます。
jQueryソリューション:
let object = new ClassName();
let $elem = $('selector');
$elem.on('click', $.proxy(object.method, object));
$elem.off('click', $.proxy(object.method, object));
これが解決策です:
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);
変更できないライブラリでこの問題が発生しました。 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>
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() {
// ...
}
}