如何在防抖机制下正确移除并重置window.resize事件监听器?
解决原生JS中移除防抖resize监听器的问题
你遇到的核心问题是:removeEventListener要求必须传入和addEventListener完全相同的函数引用才能生效,而你的防抖函数每次调用都会返回一个全新的函数实例,再加上你之前的代码里没有正确保存这个关键的引用,导致移除操作找不到对应的监听器。
问题根源拆解
- 防抖函数
debounce的特性:每次调用它都会返回一个全新的函数(闭包实例),这意味着你第一次绑定的防抖函数和第二次创建的防抖函数是完全不同的引用。 - 你之前的
functionToUnbind逻辑错误:它只是一个返回防抖函数的函数,而非防抖后的函数本身,你绑定的其实是这个外层函数,而非真正的防抖处理逻辑,这进一步加剧了引用不匹配的问题。 - IE8的
attachEvent事件名是onresize而非resize,之前的代码里也存在这个小疏漏。
修正后的解决方案
我们需要在外部作用域保存防抖函数的引用,确保每次移除和添加的是同一个函数实例:
// 在外部作用域(比如全局或模块作用域)保存防抖后的处理函数引用 let debouncedResizeHandler = null; // 你的防抖函数保持不变 function debounce(fn, wait) { var timeout; return function () { clearTimeout(timeout); timeout = setTimeout(function () { fn.apply(this, arguments) }, (wait || 1)); } } function launchStuffForLatestSliderVideo() { // 1. 先移除旧的监听器(如果存在) if (window.removeEventListener) { if (debouncedResizeHandler) { window.removeEventListener('resize', debouncedResizeHandler, false); } } else if (window.detachEvent) { // IE8及更早版本用onresize事件名 if (debouncedResizeHandler) { window.detachEvent('onresize', debouncedResizeHandler); } } // 2. 创建新的原始处理函数 const rawResizeHandler = function() { if ($videosContainer.attr('data-video-hosting') === 'youtube') { resizeVideo(netVidX, netVidY, cryptoVidX, cryptoVidY, 'youtube'); } }; // 3. 生成防抖后的函数,并保存引用 debouncedResizeHandler = debounce(rawResizeHandler, 250); // 4. 添加新的监听器 if (window.addEventListener) { window.addEventListener('resize', debouncedResizeHandler, false); } else if (window.attachEvent) { window.attachEvent('onresize', debouncedResizeHandler); } }
关键要点说明
- 保存防抖函数引用:
debouncedResizeHandler存储的是debounce()返回的闭包函数,每次调用launchStuffForLatestSliderVideo时,我们先移除这个旧引用对应的监听器,再创建新的防抖函数并更新引用。 - 匹配事件名:IE8的
attachEvent需要使用onresize作为事件名,和标准的resize区分开。 - 保持防抖函数的
this绑定:原防抖函数里的fn.apply(this, arguments)是正确的,确保resizeVideo执行时的this上下文符合预期。
这样每次切换视频时,旧的resize监听器会被正确移除,新的监听器会绑定到最新的视频尺寸逻辑上。
内容的提问来源于stack exchange,提问作者Mathieu
相关产品推荐
相关产品推荐

