removeEventListener无法移除scroll事件监听,求技术排查解决
问题分析与解决方案
核心原因
每次触发resize事件或调用winResize()时,都会在函数内部重新创建一个全新的checkFromTop函数实例。addEventListener绑定的是这个新实例的引用,而后续removeEventListener尝试移除的是另一次调用中创建的不同实例,两者引用不一致,导致无法成功移除监听。
具体问题点拆解
checkFromTop定义在winResize内部,每次winResize执行都会生成一个独立的函数对象- 当
space > '0'时,调用removeEventListener传入的是当前这次winResize里的checkFromTop,和之前addEventListener绑定的不是同一个函数,自然无法匹配移除
修复方案
把checkFromTop移到winResize外部,确保始终使用同一个函数引用;同时可以用一个变量来标记监听是否已添加,避免重复绑定:
// 把checkFromTop移到外部,保证引用唯一 function checkFromTop() { ... } // 标记监听状态,避免重复绑定 let isScrollListening = false; function winResize() { viewportWidth = window.innerWidth; viewportHeight = window.innerHeight; const $sidebar = document.querySelector('.sidebar'); const $purchaseFormFixed = document.querySelector('form.purchase-form'); if ( viewportWidth >= 1000 ) { // 改为数字比较,避免类型隐式转换问题 let sidebarHeight = $sidebar.offsetHeight; let space = viewportHeight - (sidebarHeight + 50); if ( space > 0 ) { // 同样改为数字比较 if (isScrollListening) { window.removeEventListener('scroll', checkFromTop, false); isScrollListening = false; } $sidebar.classList.add('sticky'); $purchaseFormFixed.classList.remove('show'); } else { if (!isScrollListening) { window.addEventListener('scroll', checkFromTop, false); isScrollListening = true; } $sidebar.classList.remove('sticky'); } } else { // 可选:屏幕宽度小于1000时,移除监听并重置状态 if (isScrollListening) { window.removeEventListener('scroll', checkFromTop, false); isScrollListening = false; } } } window.addEventListener('resize', winResize); winResize();
额外优化点
- 避免将数字与字符串比较(原代码
viewportWidth >= '1000'、space > '0'),直接用数字值比较更严谨,防止类型隐式转换导致的逻辑错误 - 添加监听状态标记,防止重复绑定同一个事件监听,避免回调被多次触发
内容的提问来源于stack exchange,提问作者ccdavies
相关产品推荐
相关产品推荐

