Javascript 无论如何定义回调,如何删除事件侦听器

Javascript 无论如何定义回调,如何删除事件侦听器,javascript,ecmascript-6,ecmascript-2017,Javascript,Ecmascript 6,Ecmascript 2017,多年来,我在尝试删除JavaScript中的事件侦听器时遇到了问题。通常,我必须创建一个独立的函数作为处理程序。但这只是草率的,特别是在添加了箭头函数的情况下,这只是一种痛苦 我不是要一个一次性的解决方案。无论回调是如何定义的,这都需要在所有情况下工作。这需要是原始JS,这样任何人都可以使用它。 以下代码工作正常,因为函数clickHandler是一个独特的函数,可以由addEventListener和removeEventListener使用: 此示例已更新,以显示我在过去遇到的问题 con

多年来,我在尝试删除JavaScript中的事件侦听器时遇到了问题。通常,我必须创建一个独立的函数作为处理程序。但这只是草率的,特别是在添加了箭头函数的情况下,这只是一种痛苦

我不是要一个一次性的解决方案。无论回调是如何定义的,这都需要在所有情况下工作。这需要是原始JS,这样任何人都可以使用它。

以下代码工作正常,因为函数
clickHandler
是一个独特的函数,可以由
addEventListener
removeEventListener
使用:

此示例已更新,以显示我在过去遇到的问题

constbtntest=document.getElementById('test');
设rel=null;
函数clickHandler(){
console.info('Clicked on test');
}
函数add(){
如果(rel==null){
rel=btnTest.addEventListener('click',clickHandler);
}
}
函数删除(){
btnTest.removeEventListener('click',clickHandler);
}
[…document.querySelectorAll('[cmd]')].forEach(
el=>{
const cmd=el.getAttribute('cmd');
if(窗口类型[cmd]=“函数”){
el.addEventListener('click',window[cmd]);
}
}
);
添加
去除

测试
使用闭包有一个简单的解决方案

通过将代码移动到
addEventListener
removeEventListener
的单个函数中,您可以轻松完成任务:

功能ael(el、evt、cb、选项){
log('Adding',evt',event listener for',el.outerHTML);
el.addEventListener(evt、cb、期权);
返回函数(){
log('Removing',evt',event listener for',el.outerHTML);
el.删除供应商(evt、cb、选项);
}
}
const btnTest=document.getElementById('test');
设rel=null;
函数add(){
如果(rel==null){
rel=ael(b测试,'点击',()=>{
console.info('Clicked on test');
});
}
}
函数删除(){
if(类型rel==‘函数’){
rel();
rel=null;
}
}
函数removeAll(){
rels.forEach(rel=>rel());
}
const rels=[…document.querySelectorAll('[cmd]')]。reduce(
(rels,el)=>{
const cmd=el.getAttribute('cmd');
if(窗口类型[cmd]=“函数”){
相对推送(ael(el,'点击',窗口[cmd]);
}
返回rels;
}, []
);
添加
去除
试验


删除所有
只需使用命名函数表达式:

 var el = document.querySelector('#myButton');

 el.addEventListener('click', function handler() {
   console.log('clicked');
   el.removeEventListener('click', handler); //<-- will work
 });
var el=document.querySelector(“#myButton”);
el.addEventListener('click',函数处理程序(){
console.log('clicked');
el.removeEventListener('click',handler);//您可以使用

注意:受除IE以外的所有浏览器支持

var el=document.querySelector(“#myButton”);
el.addEventListener('单击',()=>{
console.log('clicked');
},{once:true});

单击
您可以不直接使用箭头函数或任何匿名函数,并期望能够删除侦听器

要删除侦听器,需要向
removeEventListener
传递与传递给
addEventListener
完全相同的参数,但当使用匿名函数或箭头函数时,您无权访问该函数,因此无法将其传递给
removeEventListener

工作

不起作用

someElem.addEventListener('click', () => { console.log("hello"); });    
someElem.removeEventListener('click', ???) // you don't have a reference 
                                           // to the anon function so you
                                           // can't pass the correct arguments
                                           // to remove the listener
你的选择是

  • 不要使用匿名或箭头函数
  • 使用包装器跟踪参数
一个例子是@Intervalia闭包。他跟踪您传入的函数和其他参数,并返回一个您可以使用删除侦听器的函数

我经常使用的一种解决方案是跟踪所有侦听器并将其全部删除。它不是返回一个闭包,而是只允许删除所有侦听器,我发现这些侦听器在我现在构建某些内容并希望以后将其删除时很有用

函数ListenerManager(){
让侦听器={};
设nextId=1;
//返回侦听器的id。这比IMO更容易
//普通remove侦听器需要与addListener相同的参数
this.on=(elem,…args)=>{
(elem.addEventListener | | elem.on | | elem.addListener)。调用(elem,…args);
const id=nextId++;
侦听器[id]={
艾琳:艾琳,
args:args,
};
如果(参数长度<2){
抛出新错误(“参数太少”);
}
返回id;
};
this.remove=(id)=>{
const listener=listeners[id];
如果(侦听器){
删除侦听器[id];
const elem=listener.elem;
(elem.removeEventListener | | elem.removeListener).call(elem,…listener.args);
}
};
this.removeAll=()=>{
const old=侦听器;
侦听器={};
Object.keys(旧).forEach((id)=>{
const listener=old[id];
if(listener.args<2){
抛出新错误(“参数太少”);
}
const elem=listener.elem;
(elem.removeEventListener | | elem.removeListener).call(elem,…listener.args);
});
};

}
或者你只是使用jQuerys
$(某事物)。有一次(“点击“,…)
…你的例子说明了另一种情况。我感觉你在试图推销你自己的答案。我很抱歉浪费你的时间:)@intervalua我的答案仍然正确,至少第一部分是这样。
const anonFunc = () => { console.log("hello"); }
someElem.addEventListener('click', anonFunc);    
someElem.removeEventListener('click', anonFunc);  // same arguments
someElem.addEventListener('click', () => { console.log("hello"); });    
someElem.removeEventListener('click', ???) // you don't have a reference 
                                           // to the anon function so you
                                           // can't pass the correct arguments
                                           // to remove the listener