使用setTimeout结合类方法无法移除元素事件监听器的问题
问题
我实现了App类的btnInteractive方法,该方法根据传入的布尔值,为.btn--start元素添加或移除mouseover和mouseout事件监听器。点击按钮触发start方法后,先调用this.btnInteractive(true)添加监听器,2秒后通过setTimeout执行this.btnInteractive(false)尝试移除监听器,但实际监听器并未被移除,鼠标移入移出按钮仍会触发日志输出。
已做的排查操作:
- 确认
if和else代码块均已执行 - 精简代码至当前版本
- 移除
click事件监听器,无效果 - 移除
click和mouseout事件监听器,仍无效
预期效果:2秒后成功移除mouseover和mouseout事件监听器。
相关代码
'use strict'; const btnStart = document.querySelector('.btn--start'); class App { constructor() { btnStart.addEventListener('click', this.start.bind(this)); } btnInteractive(state) { console.log(`Check: ${state}`); function mouseover() { console.log('over'); } function mouseout() { console.log('out'); } if (state) { btnStart.addEventListener('mouseover', mouseover); btnStart.addEventListener('mouseout', mouseout); } else { btnStart.removeEventListener('mouseover', mouseover); btnStart.removeEventListener('mouseout', mouseout); } } start() { this.btnInteractive(true); setTimeout(() => { this.btnInteractive(false); }, 2000); } } const app = new App();
控制台输出
Check: true out over Check: false out over
解决方案
问题核心:每次调用btnInteractive时,都会创建全新的mouseover和mouseout函数。removeEventListener要求传入的函数引用必须和添加时完全一致,否则无法识别并移除。
修改方案是把事件处理函数挂载到类实例上,确保两次调用btnInteractive时使用同一个函数引用:
'use strict'; const btnStart = document.querySelector('.btn--start'); class App { constructor() { // 将事件处理函数绑定到实例,确保引用唯一 this.mouseoverHandler = this.mouseoverHandler.bind(this); this.mouseoutHandler = this.mouseoutHandler.bind(this); btnStart.addEventListener('click', this.start.bind(this)); } // 独立定义事件处理方法 mouseoverHandler() { console.log('over'); } mouseoutHandler() { console.log('out'); } btnInteractive(state) { console.log(`Check: ${state}`); if (state) { btnStart.addEventListener('mouseover', this.mouseoverHandler); btnStart.addEventListener('mouseout', this.mouseoutHandler); } else { btnStart.removeEventListener('mouseover', this.mouseoverHandler); btnStart.removeEventListener('mouseout', this.mouseoutHandler); } } start() { this.btnInteractive(true); setTimeout(() => { this.btnInteractive(false); }, 2000); } } const app = new App();
修改后,添加和移除监听器使用的是同一个函数引用,2秒后即可成功移除事件监听器,鼠标移入移出按钮不再触发日志输出。
内容的提问来源于stack exchange,提问作者Pasha
相关产品推荐
相关产品推荐

