JavaScript滚轮事件实现水平滚动卡顿问题优化咨询
解决鼠标滚轮水平滚动卡顿问题
原代码中鼠标滚轮滚动卡顿的核心原因是:直接通过scrollContainer.scrollLeft += evt.deltaY修改滚动位置是瞬间完成的硬跳转,没有过渡动画,导致视觉上的卡顿感。以下是两种可行的优化方案:
方案1:CSS原生平滑滚动(最简实现)
直接给滚动容器添加scroll-behavior: smooth样式,浏览器会自动处理平滑过渡,无需复杂JS逻辑:
main { scroll-behavior: smooth; }
同时调整滚轮事件的滚动步长,避免原生deltaY值过大导致滚动过快:
scrollContainer.addEventListener("wheel", (evt) => { evt.preventDefault(); // 用系数缩小滚动幅度,0.3可根据需求调整 const scrollStep = evt.deltaY * 0.3; scrollContainer.scrollLeft += scrollStep; });
方案2:JS自定义平滑动画(精细控制)
如果需要自定义动画曲线、滚动速度等细节,可使用requestAnimationFrame实现渐进式滚动,同时兼容原有拖拽逻辑:
const scrollContainer = document.querySelector("main"); let isDown = false; let startX; let scrollLeft; // 平滑滚动相关变量 let isScrolling = false; let targetScrollLeft = 0; // 原有拖拽逻辑保持不变 scrollContainer.addEventListener('mousedown', (e) => { isDown = true; startX = e.pageX - scrollContainer.offsetLeft; scrollLeft = scrollContainer.scrollLeft; // 拖拽时终止平滑动画,避免冲突 isScrolling = false; }); scrollContainer.addEventListener('mouseleave', () => isDown = false); scrollContainer.addEventListener('mouseup', () => isDown = false); scrollContainer.addEventListener('mousemove', (e) => { if(!isDown) return; e.preventDefault(); const x = e.pageX - scrollContainer.offsetLeft; const walk = (x - startX) * 2; scrollContainer.scrollLeft = scrollLeft - walk; // 更新目标位置,确保动画同步 targetScrollLeft = scrollContainer.scrollLeft; }); // 平滑滚动动画函数 function smoothScroll() { if (!isScrolling) return; // 计算当前位置与目标位置的差值 const diff = targetScrollLeft - scrollContainer.scrollLeft; // 用衰减系数实现减速效果,0.1可调整 const step = diff * 0.1; if (Math.abs(step) < 0.5) { // 差值足够小时直接定位,结束动画 scrollContainer.scrollLeft = targetScrollLeft; isScrolling = false; } else { scrollContainer.scrollLeft += step; requestAnimationFrame(smoothScroll); } } // 优化后的滚轮事件 scrollContainer.addEventListener("wheel", (evt) => { evt.preventDefault(); // 调整滚动步长,0.3可根据需求修改 targetScrollLeft += evt.deltaY * 0.3; // 限制滚动范围,防止超出容器边界 targetScrollLeft = Math.max(0, Math.min(targetScrollLeft, scrollContainer.scrollWidth - scrollContainer.clientWidth)); if (!isScrolling) { isScrolling = true; requestAnimationFrame(smoothScroll); } });
核心优化说明
- 步长控制:通过
evt.deltaY * 系数缩小单次滚动的幅度,避免一次性移动100px的突兀感 - 平滑过渡:无论是CSS原生特性还是JS动画,都让滚动位置在多帧中逐步变化,模拟自然的滚动惯性
- 逻辑兼容:拖拽时终止平滑动画,避免两种滚动逻辑相互干扰
内容的提问来源于stack exchange,提问作者Olivier
相关产品推荐
相关产品推荐

