You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现滚动时高亮粘性子导航菜单对应选项

实现滚动时内容容器靠近粘性导航栏的高亮导航功能

问题分析

你当前的代码仅监听了整个content容器,无法精准判断单个内容块何时靠近粘性导航栏。要实现目标,需要针对每个内容容器单独监听,并建立导航项与内容块的关联映射。

解决方案代码

<template>
  <div>
    <div id="sticky-nav" class="sticky-nav">
      <!-- 给导航项添加data-target关联对应内容块ID -->
      <a data-target="div1" class="nav-item">menu1</a>
      <a data-target="div2" class="nav-item">menu2</a>
      <a data-target="div3" class="nav-item">menu3</a>
    </div>
    <div id="content" class="content">
      <div class="content-div" id="div1">Div 1</div>
      <div class="content-div" id="div2">Div 2</div>
      <div class="content-div" id="div3">Div 3</div>      
    </div>
  </div>
</template>

<script>
export default {
  mounted() {
    const stickyNav = document.getElementById('sticky-nav');
    // 配置观察选项:以粘性导航栏为根,当内容块顶部进入导航栏下方区域时触发
    const options = {
      root: stickyNav,
      // rootMargin设为导航栏高度的负值,让内容块还没碰到导航栏就触发
      rootMargin: `-${stickyNav.clientHeight}px 0px -100vh 0px`,
      threshold: 0
    };

    const observer = new IntersectionObserver(this.handleSectionIntersect, options);
    // 监听每个内容块
    document.querySelectorAll('.content-div').forEach(div => {
      observer.observe(div);
    });
  },
  methods: {
    handleSectionIntersect(entries) {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          // 移除所有导航项的高亮类
          document.querySelectorAll('.nav-item').forEach(item => {
            item.classList.remove('active');
          });
          // 找到对应导航项并添加高亮类
          const targetNavItem = document.querySelector(`[data-target="${entry.target.id}"]`);
          if (targetNavItem) {
            targetNavItem.classList.add('active');
          }
        }
      });
    }
  }
};
</script>

<style scoped>
.sticky-nav {
  position: sticky;
  top: 0;
  background: white;
  padding: 1rem;
  border-bottom: 1px solid #eee;
}
.nav-item {
  margin-right: 1.5rem;
  text-decoration: none;
  color: #333;
}
/* 高亮样式 */
.nav-item.active {
  color: #007bff;
  font-weight: bold;
}
.content {
  padding-top: 1rem;
}
.content-div {
  height: 80vh;
  padding: 2rem;
  border-bottom: 1px solid #eee;
}
</style>

关键说明

  • 关联导航与内容块:通过data-target属性让导航项和对应内容块建立映射,方便快速找到对应关系
  • 观察配置:
    • root设为粘性导航栏,确保以导航栏为参考基准
    • rootMargin的设置是核心:-${stickyNav.clientHeight}px让内容块顶部到达导航栏底部位置就触发回调,后面的-100vh保证只有当前最靠近导航栏的内容块会被识别
  • 高亮逻辑:当内容块进入观察区域时,清除所有导航项的高亮,再给对应项添加高亮类

替代思路(无需Intersection Observer)

如果需要兼容旧浏览器,也可以监听scroll事件,通过计算位置关系实现:

mounted() {
  window.addEventListener('scroll', this.handleScroll);
},
beforeUnmount() {
  window.removeEventListener('scroll', this.handleScroll);
},
methods: {
  handleScroll() {
    const stickyNavHeight = document.getElementById('sticky-nav').clientHeight;
    const scrollTop = window.scrollY + stickyNavHeight;
    const sections = document.querySelectorAll('.content-div');
    
    sections.forEach(section => {
      const sectionTop = section.offsetTop;
      const sectionBottom = sectionTop + section.clientHeight;
      
      if (scrollTop >= sectionTop && scrollTop < sectionBottom) {
        document.querySelectorAll('.nav-item').forEach(item => item.classList.remove('active'));
        document.querySelector(`[data-target="${section.id}"]`).classList.add('active');
      }
    });
  }
}

这种方式兼容性更好,但性能略逊于Intersection Observer。

内容的提问来源于stack exchange,提问作者AWEOSOME ONE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 20:36:08