jQuery绑定鼠标滚轮实现平滑滚动动画异常冲突问题求解
滚轮整屏滚动动画冲突卡顿问题
问题表现
需要实现的交互:每次向上/向下拨动鼠标滚轮时,分别触发平滑滚动到页面顶部#top元素、页面底部#bottom元素的动画,两个区块均设置height:100vh。
实际运行异常:页面完成一次向下滚动后就会出现无规律问题,上下滚动切换时动画互相冲突、卡顿抖动,仿佛滚动操作存在冷却期,无法及时响应输入。仅极小幅度拨动鼠标滚轮时,上下滚动功能可正常双向运行,已确认问题根源为滚动输入重叠——滚轮正常滚动时会连续触发多次事件,短时间内传入过多滚动指令,导致动画队列冲突、脚本运行异常。
初始问题代码
原生jQuery animate实现
jQuery(window).bind('mousewheel DOMMouseScroll', function(event){ if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) { // 向上滚动 console.log("scroll up"); jQuery('html,body').animate({scrollTop: jQuery("#top").offset().top}, 1200, 'linear'); } else { // 向下滚动 console.log("scroll down"); jQuery('html,body').animate({scrollTop: jQuery("#bottom").offset().top}, 1200, 'linear'); } });
jQuery.scrollTo库实现
jQuery(window).bind('mousewheel DOMMouseScroll', function(event){ if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) { // 向上滚动 console.log("scroll up"); jQuery('body').scrollTo('#top', {duration:1200}); } else { // 向下滚动 console.log("scroll down"); jQuery('body').scrollTo('#bottom', {duration:1200}); } });
配套HTML结构
<div id="top" style="height:100vh;background-color: #2196f3;"></div> <div id="bottom" style="height:100vh;background-color: #009688;"></div>
问题核心原因
- 滚轮事件是高频触发事件,正常拨动一次滚轮会连续触发十几次事件回调,初始代码每次回调都会往jQuery动画队列里新增一个滚动动画,队列里的动画会依次执行,直接导致动画堆积、响应延迟
- 触发新动画前没有终止正在执行的旧动画,反向滚动时新旧动画同时作用于滚动属性,直接引发卡顿抖动
- 没有拦截原生默认滚动行为,自定义动画和浏览器原生滚动逻辑冲突
修复方案
从三个点修复即可解决问题:
- 触发新动画前调用
.stop(true)终止选中元素上所有正在执行的动画,清空待执行的动画队列 - 增加动画状态锁,动画执行期间直接拦截重复的滚轮事件,不新增动画任务,等当前动画执行完成后再解锁接收新输入
- 事件回调内先调用
event.preventDefault()阻止原生默认滚动行为,避免和自定义动画冲突
修复后可直接运行的代码:
// 滚动动画状态锁 let isAnimating = false; jQuery(window).on('mousewheel DOMMouseScroll', function(event) { // 动画执行中直接拦截重复事件 if (isAnimating) return; // 阻止原生默认滚动 event.preventDefault(); // 判断滚动方向,计算目标滚动位置 const scrollToTop = event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0; const targetOffset = scrollToTop ? jQuery('#top').offset().top : jQuery('#bottom').offset().top; // 标记动画开始,终止旧动画后执行新动画 isAnimating = true; jQuery('html, body').stop(true).animate({ scrollTop: targetOffset }, 1200, 'linear', function() { // 动画执行完成,解锁 isAnimating = false; }); });
内容的提问来源于stack exchange,提问作者Riccardo1091
相关产品推荐
相关产品推荐

