如何用wheel事件替代scroll事件实现导航栏对应区块的active状态高亮
问题原因
Locomotive Scroll这类平滑滚动类库会接管页面滚动逻辑,通过修改容器transform属性实现滚动效果,不会触发原生window的scroll事件,同时原生scrollY、offsetTop等属性获取的数值也和实际滚动位置不匹配,所以原有代码失效。
修复方案
直接使用Locomotive Scroll提供的内置滚动事件监听即可,不需要改用wheel事件实现。
第一步:绑定Locomotive Scroll的scroll事件
在你初始化Locomotive Scroll的代码后,绑定它自带的scroll事件,从回调参数中直接获取当前滚动位置等信息。
第二步:修正元素位置计算逻辑
因为Locomotive Scroll会给滚动容器添加transform位移,需要用getBoundingClientRect()配合滚动位置计算区块的实际相对位置,避免offsetTop的计算误差。
完整可运行代码
const sections = document.querySelectorAll("section"); const navLinks = document.querySelectorAll("nav a"); // 初始化Locomotive Scroll(和你原有初始化逻辑保持一致即可) const scroll = new LocomotiveScroll({ el: document.querySelector('[data-scroll-container]'), smooth: true }); // 绑定Locomotive的内置滚动事件 scroll.on('scroll', (instance) => { let current = ""; // instance.scroll.y就是当前的滚动距离,替代原生scrollY const scrollY = instance.scroll.y; sections.forEach(section => { const sectionTop = section.getBoundingClientRect().top + scrollY; const sectionHeight = section.clientHeight; if (scrollY >= sectionTop - sectionHeight / 3) { current = `#${section.getAttribute("id")}`; } }); // 更新导航链接激活状态 navLinks.forEach(each => { each.classList.remove("nav-active"); if (each.getAttribute("href") === current) { each.classList.add("nav-active"); } }); });
其他平滑滚动类库通用兼容思路
如果用的是其他类似的自定义滚动库,都可以套用这个逻辑:
- 优先查找库官方提供的滚动监听事件,从回调参数中获取当前滚动距离
- 元素位置计算统一用
getBoundingClientRect()+ 滚动距离的方式,避免offsetTop在transform位移场景下的计算误差 - 不要用
wheel事件实现,wheel事件只能监听鼠标滚轮操作,无法兼容拖拽滚动、键盘滚动、点击锚点跳转等滚动场景,会有大量边界问题
内容的提问来源于stack exchange,提问作者fay
相关产品推荐
相关产品推荐

