如何用原生JavaScript实现jQuery animate(scrollLeft)的菜单滚动效果?
原生JS实现菜单左右滚动替代jQuery animate()
我需要把以下实现菜单左右滚动的jQuery animate() 代码转换成原生JavaScript:
$(document).ready( function() { $('#btn-menu-nav-previous').click(function() { $(".menu-inner-box").animate({scrollLeft: "-=100px"}); }); $('#btn-menu-nav-next').click(function() { $(".menu-inner-box").animate({scrollLeft: "+=100px"}); }); });
这段代码原本通过点击「上一页」和「下一页」按钮实现菜单列表的分页滚动。我尝试写了原生JS版本,但完全无法正常工作,代码如下:
HTML
<nav id="menu-container" class="arrow"> <div id="btn-menu-nav-previous" style="fill: #FFF"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"> <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" /> <path d="M0 0h24v24H0z" fill="none" /> </svg> </div> <div id="btn-menu-nav-next"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"> <path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" /> <path d="M0 0h24v24H0z" fill="none" /> </svg> </div> <div class="menu-inner-box"> <div class="menu"> <a class="menu-item" href="#">Menu 1</a> <a class="menu-item" href="#">Menu 2</a> <a class="menu-item" href="#">Menu 3</a> <a class="menu-item" href="#">Menu 4</a> <a class="menu-item" href="#">Menu 5</a> <a class="menu-item" href="#">Menu 6</a> <a class="menu-item" href="#">Menu 7</a> <a class="menu-item" href="#">Menu 8</a> <a class="menu-item" href="#">Menu 9</a> <a class="menu-item" href="#">Menu 10</a> <a class="menu-item last-item" href="#">Menu 11</a> </div> </div> </nav>
CSS
nav#menu-container { background: #586e75; position: relative; width: 50%; height: 56px; } #btn-menu-nav-previous { text-align: center; color: white; cursor: pointer; font-size: 24px; position: absolute; left: 0px; padding: 9px 12px; background: #8f9a9d; fill: #FFF; } #btn-menu-nav-next { text-align: center; color: white; cursor: pointer; font-size: 24px; position: absolute; right: 0px; padding: 9px 12px; background: #8f9a9d; fill: #FFF; } .menu-inner-box { width: 100%; white-space: nowrap; margin: 0 auto; overflow: hidden; padding: 0px 54px; box-sizing: border-box; } .menu { padding: 0; margin: 0; list-style-type: none; display: block; text-align: center; } .menu-item { height: 100%; padding: 0px 25px; color: #fff; display: inline; margin: 0 auto; line-height: 57px; text-decoration: none; text-align: center; white-space: no-wrap; } .menu-item:hover { text-decoration: underline; } .last-item { margin-right: 50px; }
尝试的原生JS代码
document.addEventListener("DOMContentLoaded", function() { var menu = document.querySelector(".menu-inner-box"); var prev = document.getElementById("btn-menu-nav-previous"); var next = document.getElementById("btn-menu-nav-next"); prev.addEventListener("click", function() { menu.animate([{ scrollLeft: menu.scrollLeft }, { scrollLeft: menu.scrollLeft - 100 }], { duration: 500, fill: "forwards" }); }); next.addEventListener("click", function() { menu.animate([{ scrollLeft: menu.scrollLeft }, { scrollLeft: menu.scrollLeft + 100 }], { duration: 500, fill: "forwards" }); }); });
问题原因及修复方案
你的原生JS代码无法工作的核心问题是:Element.animate() 仅创建视觉动画效果,不会真正修改元素的 scrollLeft 属性,动画结束后元素会回到初始滚动位置,因此看起来没有效果。
方案1:使用原生 scrollBy() 平滑滚动(推荐)
现代浏览器支持 scrollBy() 的 behavior: 'smooth' 参数,一行代码即可实现平滑滚动:
document.addEventListener("DOMContentLoaded", function() { const menu = document.querySelector(".menu-inner-box"); const prevBtn = document.getElementById("btn-menu-nav-previous"); const nextBtn = document.getElementById("btn-menu-nav-next"); prevBtn.addEventListener("click", () => { menu.scrollBy({ left: -100, behavior: 'smooth' }); }); nextBtn.addEventListener("click", () => { menu.scrollBy({ left: 100, behavior: 'smooth' }); }); });
方案2:手动实现动画逻辑(兼容旧浏览器)
如果需要兼容不支持平滑滚动的旧浏览器,可以通过定时器逐步修改 scrollLeft 值:
document.addEventListener("DOMContentLoaded", function() { const menu = document.querySelector(".menu-inner-box"); const prevBtn = document.getElementById("btn-menu-nav-previous"); const nextBtn = document.getElementById("btn-menu-nav-next"); let isScrolling = false; // 防止重复触发动画 function animateScroll(targetScrollLeft, duration = 500) { if (isScrolling) return; isScrolling = true; const startScrollLeft = menu.scrollLeft; const distance = targetScrollLeft - startScrollLeft; const startTime = performance.now(); function step(currentTime) { const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); // 缓动函数让动画更自然 const easeProgress = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2; menu.scrollLeft = startScrollLeft + distance * easeProgress; if (progress < 1) { requestAnimationFrame(step); } else { isScrolling = false; } } requestAnimationFrame(step); } prevBtn.addEventListener("click", () => { animateScroll(menu.scrollLeft - 100); }); nextBtn.addEventListener("click", () => { animateScroll(menu.scrollLeft + 100); }); });
另外,你CSS里的 .menu-item 存在拼写错误:white-space: no-wrap 应改为 white-space: nowrap,确保菜单项保持一行显示。
内容的提问来源于stack exchange,提问作者user21345056
相关产品推荐
相关产品推荐

