使用window.requestAnimationFrame迁移jQuery横向滚动代码遇向左滚动失效问题
问题分析与修复方案
核心问题
你的原生JS代码仅向右滚动有效,向左滚动失效的原因是滚动终止条件判断错误:
- 向右滚动时,目标位置
endLocation大于起始位置startLocation,window.pageXOffset <= endLocation的条件能正常触发动画循环; - 向左滚动时,
endLocation小于startLocation,初始的window.pageXOffset(起始位置)就不满足<= endLocation,导致动画只执行一次就停止。
另外还有两个细节问题:
- 原代码仅给第一个匹配的图片绑定了点击事件,和jQuery版本的“所有图片绑定”逻辑不一致;
- 基于固定步数的增量计算不够稳定,不同设备上的动画时长会有差异。
修复后的代码
下面是兼容左右滚动、匹配jQuery原逻辑、动画时长稳定的原生JS实现:
// 给所有匹配的图片绑定点击事件 document.querySelectorAll('.page-template-format-horizontal .exhibit-image').forEach(img => { img.addEventListener('click', function (e) { // 计算目标滚动位置,和jQuery逻辑一致 const slideWidth = e.currentTarget.getBoundingClientRect().width; const windowWidth = window.innerWidth; const scrollTo = e.currentTarget.offsetLeft; const targetOffset = scrollTo - (windowWidth / 2) + (slideWidth / 2); const duration = 500; // 和jQuery一致的500ms动画时长 const startX = window.pageXOffset; const distance = targetOffset - startX; const startTime = performance.now(); // 基于时间驱动的动画步骤,保证时长稳定 function animateScroll(currentTime) { const elapsed = currentTime - startTime; // 计算动画进度(0到1),这里用线性缓动,可替换为其他缓动函数 const progress = Math.min(elapsed / duration, 1); // 计算当前需要滚动到的位置 const currentX = startX + distance * progress; window.scrollTo(currentX, window.pageYOffset); // 进度未到1则继续执行动画 if (progress < 1) { window.requestAnimationFrame(animateScroll); } } window.requestAnimationFrame(animateScroll); e.preventDefault(); }); });
关键改进点
- 滚动条件修复:用
progress < 1作为循环终止条件,不管滚动方向都能正常触发动画; - 批量绑定事件:使用
querySelectorAll遍历所有图片,和jQuery的事件绑定逻辑对齐; - 时间驱动动画:通过
performance.now()计算动画进度,保证在不同设备上都能稳定维持500ms的动画时长; - 可扩展缓动:如果需要更自然的滚动效果,可以替换
progress的计算逻辑,比如使用ease-in-out缓动:// ease-in-out缓动函数 const progress = elapsed / duration; const easedProgress = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;
内容的提问来源于stack exchange,提问作者leemon
相关产品推荐
相关产品推荐

