首页 > 解决方案 > 无法移除 eventListener,尝试了 6 小时

问题描述

我已经尝试了几个小时删除事件侦听器而没有任何成功。

由于我进行的测试,我了解到问题可能在于听众参考。

这是代码。为了清楚起见,我剥离并简化了所有内容。

    const COMPLETE = 'complete';
    let dispatcher = new EventTarget;

    class Template {
        complete(e){
            e.currentTarget.removeEventListener(COMPLETE, this.complete);
            console.log('I run only once');
        }
    }

    let child = new Template();
    child.exe = function(){
        dispatcher.addEventListener(COMPLETE, this.complete.bind(this));
    }
    child.exe();


    
    dispatcher.dispatchEvent(new Event(COMPLETE));
    dispatcher.dispatchEvent(new Event(COMPLETE));
    dispatcher.dispatchEvent(new Event(COMPLETE));

当然在控制台中你可以读三遍“我只运行一次”。

我所做的测试涉及额外的变量“functionReference”,我在其中存储侦听器引用。然后它工作。

    let functionReference
    const COMPLETE = 'complete';

    let dispatcher = new EventTarget;

    class Template {
        complete(e){
            e.currentTarget.removeEventListener(COMPLETE, functionReference);
            console.log('i run only once');
        }
    }

    let child = new Template();
    child.exe = function(){
        functionReference = this.complete.bind(this);
        dispatcher.addEventListener(COMPLETE, functionReference);
    }
    child.exe();


    
    dispatcher.dispatchEvent(new Event(COMPLETE));
    dispatcher.dispatchEvent(new Event(COMPLETE));
    dispatcher.dispatchEvent(new Event(COMPLETE));

现在在控制台中只有一次“我只运行一次”。

怎么了?为什么我不能删除那个监听器?

*****更新/解决方案如下 ***非常感谢 Teemu 和 amrender singh


感谢 amrender singh 的解释!并感谢 Teemu 的好主意和解决方案!非常感谢您的快速帮助!多年来,我没有被困得这么厉害。

以下 Teemu 解决方案:

const COMPLETE = 'complete';
let dispatcher = new EventTarget;

class Template {
    constructor(){
        this.complete = (e)=>{
            e.currentTarget.removeEventListener(COMPLETE, this.complete);
            console.log('i run only once');
        }
    }
}

let child = new Template();
child.exe = function(){
    dispatcher.addEventListener(COMPLETE, this.complete);
}
child.exe();



dispatcher.dispatchEvent(new Event(COMPLETE));
dispatcher.dispatchEvent(new Event(COMPLETE));
dispatcher.dispatchEvent(new Event(COMPLETE));

或者,可以存储对侦听器的引用并将其作为变量传递。

标签: javascriptremoveeventlistener

解决方案


来自 MDN:

bind() 方法创建一个新函数,在调用该函数时,将其 this 关键字设置为提供的值,并在调用新函数时提供的任何参数之前具有给定的参数序列。

在第一个示例中:

dispatcher.addEventListener(COMPLETE, this.complete.bind(this));

绑定创建一个新函数并将其附加为处理程序。这就是为什么您无法删除事件侦听器的原因,因为您之前使用 bind 附加的事件侦听器与您的完整方法不同。

在您的第二个示例中:

functionReference = this.complete.bind(this);
dispatcher.addEventListener(COMPLETE, functionReference);

您正在将 bind 返回的新函数注册为侦听器,然后将其删除,因为在添加/删除中,侦听器都是相同的,这就是它被删除的原因。


推荐阅读