滚动时导航项放大及菜单高亮JS代码失效求助
问题与解决方案:滚动导航高亮+放大效果
问题说明
我想要实现滚动时导航栏菜单项放大的效果,但现有负责滚动高亮菜单的JavaScript代码完全不工作——滚动时console.log(pageXOffset)或console.log(sectionLeft)都没有输出,根本没法排查问题。
代码问题排查
- 滚动事件绑定错误:页面的横向滚动是在
.inner-wrapper容器内,而非window全局,绑定window的scroll事件不会触发,导致console无输出。 - 变量未声明/使用错误:循环变量
i未用let/var声明,造成全局污染;操作导航项时误用未定义的navbarItem,应该用已获取的navLi。 - 逻辑判断错误:判断nav项匹配时用了赋值运算符
=,而非全等比较===;匹配逻辑错误,未将section的id与nav项的href对应。 - 元素位置计算不准确:用
offsetLeft获取位置受父元素布局影响,改用getBoundingClientRect()更可靠。
修正后的完整代码
HTML
</head> <body> <header> <nav id="navbar"> <ul id="navbarlist"> <li class="navbarItem home"><a href="#home">home</a></li> <li class="navbarItem about"><a href="#about">about</a></li> <li class="navbarItem products"><a href="#products">products</a></li> <li class="navbarItem services"><a href="#services">services</a></li> <li class="navbarItem contactus"><a href="#contactus">contact us</a></li> </ul> </nav> </header> <main> <div class="outer-wrapper"> <div class="inner-wrapper"> <section class="sections" id="home"></section> <section class="sections" id="about"></section> <section class="sections" id="products"></section> <section class="sections" id="services"></section> <section class="sections" id="contactus"></section> </div> </div> </main> </body> </html>
CSS
#navbar{ position: absolute; width: 50vw; left: calc(50vw - 25vw); } #navbarlist{ top: 50px; left: 25vw; width: 50vw; position: fixed; display: flex; justify-content: space-between; z-index: 1; padding: 0; list-style: none; /* 移除默认列表样式 */ } .navbarItem{ display: flex; justify-content: center; align-items: center; color: #000; opacity: 0.5; width: 100px; height: 100px; border-radius: 50%; transition: all 0.3s ease; /* 添加过渡动画,让放大更平滑 */ } .navbarItem:hover{ transform: scale(1.5); margin-top: 30px; } .active{ transform: scale(1.3); margin-top: 10px; color: aqua; opacity: 1; /* 高亮时完全不透明 */ } .sections{ width: 100vw; height: 100vh; /* 给section设置高度,方便滚动测试 */ flex-shrink: 0; /* 防止section被压缩 */ } /* 给不同section加背景色区分 */ #home { background: #f0f0f0; } #about { background: #e0e0e0; } #products { background: #d0d0d0; } #services { background: #c0c0c0; } #contactus { background: #b0b0b0; } .outer-wrapper{ width: 100vw; height: 100vh; overflow: hidden; /* 隐藏外部滚动条 */ } .inner-wrapper{ display: flex; height: 100vh; overflow-x: auto; /* 开启横向滚动 */ scroll-snap-type: x mandatory; /* 可选:滚动吸附到section */ } .sections{ scroll-snap-align: start; /* 可选:滚动吸附对齐 */ }
JavaScript
<script> const sections = document.querySelectorAll('section'); const navLi = document.getElementsByClassName('navbarItem'); const innerWrapper = document.querySelector('.inner-wrapper'); // 绑定容器的滚动事件,而非window innerWrapper.addEventListener('scroll', changeOnScroll); function changeOnScroll(){ let currentId = ""; // 获取容器的水平滚动距离 const scrollLeft = innerWrapper.scrollLeft; // 获取容器的视口宽度 const viewportWidth = innerWrapper.clientWidth; for(let i = 0; i < sections.length; i++){ const section = sections[i]; // 获取section相对于容器的位置 const rect = section.getBoundingClientRect(); // 当section进入视口一半以上时,标记为当前section if(rect.left <= viewportWidth / 2 && rect.right >= viewportWidth / 2){ currentId = section.getAttribute('id'); break; // 找到第一个匹配的就跳出循环 } } // 更新导航项的高亮状态 for(let i = 0; i < navLi.length; i++){ const navItem = navLi[i]; navItem.classList.remove('active'); // 匹配nav项的href与section的id if(navItem.querySelector('a').getAttribute('href') === `#${currentId}`){ navItem.classList.add('active'); } } } // 初始加载时执行一次,确保默认高亮正确 changeOnScroll(); </script>
关键修改说明
- 滚动事件绑定:改为监听
.inner-wrapper的scroll事件,确保滚动时触发函数。 - 位置判断逻辑:用
getBoundingClientRect()获取section的视口位置,判断是否进入视口中心,匹配更准确。 - 导航匹配逻辑:通过nav项的href属性与section的id对应,避免索引错位问题。
- 过渡动画:给
.navbarItem添加transition属性,让放大/缩小效果更平滑。 - 初始执行:页面加载时调用一次
changeOnScroll(),确保默认状态正确。
内容的提问来源于stack exchange,提问作者mob x
相关产品推荐
相关产品推荐

