如何控制mousewheel事件触发间隔?视频滚动切换功能异常求助
问题排查与解决方案
看起来你遇到的核心问题是定时器堆积导致的锁机制失效,另外还有解锁时机不合理的问题,咱们一步步拆解:
问题根源分析
错误使用
setInterval而非setTimeout:
每次触发滚轮事件时,你都会创建一个新的setInterval定时器——这个定时器会每2秒重复把animating设为false。如果短时间内触发多次滚轮(比如触控板快速滚动),就会同时存在多个定时器,它们会陆续把animating解锁,导致后续的滚轮事件又能触发,直接跳过多个视频。解锁时机不匹配实际操作时长:
你的滚动动画只需要500ms,但你固定设置2秒后解锁,不仅没必要,还会在动画完成后留下很长的空白期,而如果这期间又有定时器触发,就会提前解锁。未清除重复定时器:
没有对之前的定时器做清除操作,导致多个定时器同时运行,互相干扰animating的状态。
修复后的完整代码
let animating = false; let timer = null; // 用来存储定时器ID,方便清除 let i = 1; const goToNextVideo = function (callback) { if (i === 4) { // 总共4个视频 callback(); // 即使不跳转,也要触发回调解锁 return; } $('html, body').animate( { scrollTop: $(`.video-${i + 1}`).offset().top }, 500, function() { // 动画完成后执行操作 $(`.video-${i + 1}`).get(0).play(); $(`.video-${i}`).get(0).pause(); i += 1; callback(); // 动画完成后解锁 } ); }; const goToPreviousVideo = function (callback) { if (i === 1) { callback(); return; } $('html, body').animate( { scrollTop: $(`.video-${i - 1}`).offset().top }, 500, function() { $(`.video-${i}`).get(0).pause(); $(`.video-${i - 1}`).get(0).play(); i -= 1; callback(); // 动画完成后解锁 } ); }; // 绑定滚轮事件,用.on()代替.bind()(jQuery推荐写法) $(window).on('mousewheel', function (event) { // 如果正在动画或视频正在播放,直接返回 if (actuallyPlaying || animating) return; // 先清除之前的定时器,避免堆积 if (timer) clearTimeout(timer); animating = true; const unlock = function() { animating = false; timer = null; }; if (event.originalEvent.wheelDelta >= 0) { goToPreviousVideo(unlock); } else { goToNextVideo(unlock); } // 加一个保底的解锁机制,防止动画回调意外不触发 timer = setTimeout(unlock, 1000); });
关键改进点说明
- 用
setTimeout替代setInterval:我们只需要在操作完成后解锁一次,不需要重复执行,setTimeout更合适。 - 动画回调触发解锁:滚动动画完成后才解锁,确保用户必须等当前切换完成才能触发下一次操作,完全贴合实际操作时长。
- 清除重复定时器:每次触发事件时先清除之前的定时器,避免多个定时器同时修改
animating状态。 - 保底解锁机制:防止动画回调因为某些意外(比如元素不存在)没触发,导致永远锁死的情况。
- 优化事件绑定:用jQuery推荐的
.on()代替.bind(),兼容性和灵活性更好。
这样修改后,不管是鼠标滚轮还是触控板滚动,都能保证每次只能触发一次视频切换,不会出现连续跳的问题了!
内容的提问来源于stack exchange,提问作者Jivoli




