Vue中如何通过IntersectionObserver/Scrollspy给对应section导航加自定义激活类
问题根因
Vue Router默认的router-link-active、router-link-exact-active类是通过匹配路由路径来判定激活状态的,你所有导航链接的路由路径都是/,仅hash锚点不同,因此默认逻辑会把所有同路径的链接都标记为激活,需要自行通过滚动监听来控制激活状态。
解决方案
1. 修改导航模板,绑定动态激活类
放弃依赖Router自带的激活类,自定义激活类,通过变量控制当前激活的导航项:
<template> <nav> <router-link to="/" :class="{ 'nav-active': currentActive === 'home' }" >Home</router-link> <router-link to="/#about" :class="{ 'nav-active': currentActive === 'about' }" >About</router-link> <router-link to="/#contact" :class="{ 'nav-active': currentActive === 'contact' }" >Contact</router-link> </nav> <!-- 你的section代码 --> <section id="home">Home</section> <section id="about">About</section> <section id="contact">Contact</section> </template>
2. 新增滚动监听逻辑,动态更新激活状态
监听页面滚动事件,判定当前视口内展示的section,更新激活变量:
以下为Vue3 Composition API示例:
<script setup> import { ref, onMounted, onUnmounted } from 'vue' // 存储当前激活的section id const currentActive = ref('home') // 所有需要监听的section id列表 const sectionList = ['home', 'about', 'contact'] // 滚动偏移量,适配固定头部的场景,值和头部高度保持一致即可 const OFFSET = 80 const scrollHandler = () => { const scrollY = window.scrollY + OFFSET sectionList.forEach(id => { const sectionEl = document.getElementById(id) if (!sectionEl) return const sectionTop = sectionEl.offsetTop const sectionHeight = sectionEl.offsetHeight // 判定滚动位置是否落在当前section范围内 if (scrollY >= sectionTop && scrollY < sectionTop + sectionHeight) { currentActive.value = id } }) } onMounted(() => { window.addEventListener('scroll', scrollHandler) // 页面初始化/刷新时执行一次,适配直接访问带锚点链接的场景 scrollHandler() }) onUnmounted(() => { window.removeEventListener('scroll', scrollHandler) }) </script>
如果你用的是Vue2,把逻辑对应迁移到选项式API的data、mounted、beforeDestroy生命周期即可。
3. 自定义激活类样式
.nav-active { color: #3b82f6; font-weight: 600; border-bottom: 2px solid #3b82f6; /* 按需修改你需要的激活样式 */ }
可选优化:配置路由平滑滚动
如果需要点击导航时平滑滚动到对应section,可以在Router配置中新增scrollBehavior配置:
// Vue Router 4.x 示例 import { createRouter, createWebHistory } from 'vue-router' const router = createRouter({ history: createWebHistory(), routes: [/* 你的路由配置 */], scrollBehavior(to) { if (to.hash) { return { el: to.hash, behavior: 'smooth', // 偏移量和上面的OFFSET保持一致,适配固定头部 top: 80 } } return { top: 0 } } })
内容的提问来源于stack exchange,提问作者Shubhang Chourasia
相关产品推荐
相关产品推荐

