Vue2动态类绑定失效:导航栏无法高亮当前所在区块
Vue2导航高亮:Intersection Observer无法更新data的修复方案
问题根源
你遇到的核心问题是Intersection Observer回调函数的this指向错误:使用普通function定义回调时,this指向的是Observer实例本身,而非Vue组件实例。所以你修改的this.activeEntry并不是Vue data里的变量,控制台打印的只是Observer对象上新增的属性,自然无法触发视图更新。
修复方法(两种可选)
方法1:改用箭头函数定义回调
箭头函数会继承外部作用域的this(也就是Vue组件实例),直接修改data变量:
mounted() { this.observer = new IntersectionObserver( (entries) => { // 替换为箭头函数 const active = entries.filter((e) => e.isIntersecting); if (active.length) { this.activeEntry = active[0].target.childNodes[0].id; console.log(this.activeEntry); // 现在指向Vue的data变量 } }, { threshold: [0.5] } ); // 监听逻辑简化为forEach遍历 const matches = document.querySelectorAll("section.box"); matches.forEach(item => this.observer.observe(item)); }
方法2:提前保存Vue实例的引用
如果习惯用普通函数,可以在回调外把Vue实例存起来:
mounted() { const vm = this; // 保存Vue实例引用 this.observer = new IntersectionObserver( function(entries) { const active = entries.filter((e) => e.isIntersecting); if (active.length) { vm.activeEntry = active[0].target.childNodes[0].id; // 用vm访问data console.log(vm.activeEntry); } }, { threshold: [0.5] } ); const matches = document.querySelectorAll("section.box"); matches.forEach(item => this.observer.observe(item)); }
额外优化建议
- 避免依赖
childNodes[0]:childNodes[0]容易受DOM结构变化影响,建议直接给监听的section设置data-id属性:
然后在回调里取标识:<section class="box" data-id="Entry-c">...</section>this.activeEntry = active[0].target.dataset.id; - 清理Observer避免内存泄漏:在组件销毁时停止监听:
beforeDestroy() { if (this.observer) { const matches = document.querySelectorAll("section.box"); matches.forEach(item => this.observer.unobserve(item)); this.observer.disconnect(); } }
修改后的完整代码
<template> <div id="Navigation-c"> <ul> <li :class="{ active: activeEntry == 'Entry-c' }" v-scroll-to="'#Entry-c'"> <font-awesome-icon icon="fa-solid fa-chevron-up" /> </li> <li :class="{ active: activeEntry == 'Motivation-c' }" v-scroll-to="'#Motivation-c'"> <p>Intro</p> </li> <li :class="{ active: activeEntry == 'NeuralNetworks-c' }" v-scroll-to="'#NeuralNetworks-c'"> <p>AI</p> </li> <li :class="{ active: activeEntry == 'About-c' }" v-scroll-to="'#About-c'"> <p>About</p> </li> <li :class="{ active: activeEntry == 'Contact-c' }" v-scroll-to="'#Contact-c'"> <p>Contact</p> </li> </ul> </div> </template> <script> export default { name: "Navigation-c", data: () => ({ activeEntry: '', observer: null }), mounted() { this.observer = new IntersectionObserver( (entries) => { const active = entries.filter((e) => e.isIntersecting); if (active.length) { // 若section已设置data-id,建议改用下面一行 // this.activeEntry = active[0].target.dataset.id; this.activeEntry = active[0].target.childNodes[0].id; } }, { threshold: [0.5] } ); const matches = document.querySelectorAll("section.box"); matches.forEach(item => this.observer.observe(item)); }, beforeDestroy() { if (this.observer) { const matches = document.querySelectorAll("section.box"); matches.forEach(item => this.observer.unobserve(item)); this.observer.disconnect(); } } }; </script> <style lang="scss" scoped> .active { color: red !important; } </style>
内容的提问来源于stack exchange,提问作者Kilian Kramer
相关产品推荐
相关产品推荐

