vue点击导航滚动到相应位置,鼠标滚动到相应位置对应导航名称高亮

html:

html 复制代码
<template>
   <div style="display: flex;justify-content: space-between;align-items: center;">
   <!-- 左侧是滚动内容 -->
 	 <div style="width: 80%">
 	   <!-- 每个card都有对应的id -->
 	    <el-card style="margin-bottom: 6px;" id="section-1">
          <div slot="header" style="font-size: 20px;font-weight: 700;display: flex;">
            <div style="background-color: #409eff;width: 4px;height: 20px; border-radius: 2px;margin-left: -21px;margin-right: 10px;"></div>
            <div>综合评价1</div>
          </div>
          <div>内容一</div>
         </el-card>
         
         <el-card style="margin-bottom: 6px;" id="section-2">
          <div slot="header" style="font-size: 20px;font-weight: 700;display: flex;">
            <div style="background-color: #409eff;width: 4px;height: 20px; border-radius: 2px;margin-left: -21px;margin-right: 10px;"></div>
            <div>综合评价2</div>
          </div>
          <div>内容二</div>
         </el-card>
         
         <el-card style="margin-bottom: 6px;" id="section-3">
          <div slot="header" style="font-size: 20px;font-weight: 700;display: flex;">
            <div style="background-color: #409eff;width: 4px;height: 20px; border-radius: 2px;margin-left: -21px;margin-right: 10px;"></div>
            <div>综合评价3</div>
          </div>
          <div>内容三</div>
         </el-card>
         <el-card style="margin-bottom: 6px;" id="section-4">
          <div slot="header" style="font-size: 20px;font-weight: 700;display: flex;">
            <div style="background-color: #409eff;width: 4px;height: 20px; border-radius: 2px;margin-left: -21px;margin-right: 10px;"></div>
            <div>综合评价4</div>
          </div>
          <div>内容四</div>
         </el-card>
         <el-card style="margin-bottom: 6px;" id="section-5">
          <div slot="header" style="font-size: 20px;font-weight: 700;display: flex;">
            <div style="background-color: #409eff;width: 4px;height: 20px; border-radius: 2px;margin-left: -21px;margin-right: 10px;"></div>
            <div>综合评价5</div>
          </div>
          <div>内容五</div>
         </el-card>
 	  </div>


 	  <!-- 右侧是导航栏,用elementui的时间线组件 el-timeline-item 来展示 -->
 	  <!-- 导航分为父级和子级两层,一个父级包含多个子级,可以参考 navItems 数据格式 -->
 	  <!--  :hide-timestamp="item.title === '回到顶部'" ------------只有回到顶部 才隐藏时间戳 -->
 	  <!--  :color="currentSectionParent === index ? item.color : ''" ------------给选中的导航节点添加颜色展示 -->
 	  <!-- :class="{'activeNav': currentSection == obj.id}"  ------------给当前点击的导航名称添加颜色展示 -->
 	  <div style="width: 20%">
 	  	<div style="width: 11%" class="rightNav">
        <el-timeline>
          <el-timeline-item 
            v-for="(item, index) in navItems" 
            :key="index" 
            :timestamp="item.title" 
            :hide-timestamp="item.title === '回到顶部'"
            :color="currentSectionParent === index ? item.color : ''"
            placement="top"  
            >
            <div 
              v-for="(obj,idx) in item.children" 
              :key="idx" 
              @click="scrollTo(obj,idx,index)"
              class="navTtem"
              :class="{'activeNav': currentSection == obj.id}"
              >
                {{ obj.title }}
            </div>
          </el-timeline-item>
        </el-timeline>
        </div>
 	  </div>
   </div>

</template>

js:

javascript 复制代码
data () {
   return {
     currentSection: 'section-1', // 默认高亮第一个
     currentSectionParent: 0,
     navItems: [
        {
          title: '导航1', 
          color: '#409eff',
          children: [{title: '导航1-1', id: 'section-1'}]
        },
        {
          title: '导航2',
          color: '#409eff',
          children: [
            {title: '导航2-1', id: 'section-2'},
            {title: '导航2-2', id: 'section-3'},
            {title: '导航2-2', id: 'section-4'},
          ]
        },
        {
          title: '导航3',
          color: '#409eff',
          children: [{title: '导航3-1', id: 'section-5'}]
        },
        {
          title: '回到顶部',
          children: [{title: '回到顶部', id: 'section-6'}]
        }
      ]
     
   }
}
// mounted 和 beforeDestroy 生命周期钩子:分别在组件挂载时和销毁前添加和移除滚动事件监听器
mounted () {
  window.addEventListener('scroll', this.handleScroll);
},
beforeDestroy() {
  window.removeEventListener('scroll', this.handleScroll);
},
methods: {
   // 点击导航时,使用 scrollIntoView 方法平滑滚动到相应位置,并更新 currentSection 和 currentSectionParent 的值来高亮导航项
   scrollTo (obj,idx,index) {
      // 回到顶部
      if (obj.id === 'section-6') {
        window.scrollTo({ top: 0, behavior: 'smooth' });
        return
      }
      
      this.currentSection = obj.id
      this.currentSectionParent = index
      const el = document.getElementById(obj.id);
      if (el) {
        el.scrollIntoView({ behavior: 'smooth' });
      }
    },
    
    // handleScroll 方法:监听滚动事件,计算当前滚动的位置,根据滚动位置更新 currentSection 和 currentSectionParent 
    handleScroll() {
      const scrollPosition = window.scrollY;
      this.navItems.forEach((item,index) => {
        item.children.forEach((obj) => {
          const element = document.getElementById(obj.id);
          if (element) {
            const elementTop = element.offsetTop;
            const elementBottom = elementTop + element.clientHeight;
            if (scrollPosition >= elementTop && scrollPosition < elementBottom) {
              this.currentSection = obj.id;
              this.currentSectionParent = index
            }
          }
         })
        
      });
    },
},
  

css:

html 复制代码
<style lang="scss" scoped>
::v-deep .el-timeline {
  padding-left: 15px;
}
::v-deep .el-timeline-item {
  padding-bottom: 0px;
}
::v-deep .el-timeline-item__timestamp.is-top {
  margin-bottom: 5px;
}
::v-deep .el-timeline-item__wrapper {
  padding-left: 20px;
}

.rightNav {
 position: fixed;
 top: 50%;
 right: 10px;
}
.navTtem {
  padding: 3px 0;
  font-size: 12px;
  cursor: pointer;
}
.activeNav{
  color: #409eff;
}
</style>

效果图(数据对不上,但是展示效果是一样的)

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/03c89a119a1f4100915664957c8c5069.png

相关推荐
zhangjr057518 分钟前
【HarmonyOS Next】鸿蒙实用装饰器一览(一)
前端·harmonyos·arkts
不爱学习的YY酱30 分钟前
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
java·linux·前端·算法·操作系统
zongzi_49435 分钟前
二次封装的天气时间日历选择组件
开发语言·javascript·ecmascript
木子七1 小时前
vue2-vuex
前端·vue
麻辣_水煮鱼1 小时前
vue数据变化但页面不变
前端·javascript·vue.js
BY—-组态1 小时前
web组态软件
前端·物联网·工业互联网·web组态·组态
一条晒干的咸魚1 小时前
【Web前端】实现基于 Promise 的 API:alarm API
开发语言·前端·javascript·api·promise
WilliamLuo2 小时前
MP4结构初识-第一篇
前端·javascript·音视频开发
Beekeeper&&P...2 小时前
web钩子什么意思
前端·网络
过期的H2O22 小时前
【H2O2|全栈】JS进阶知识(七)ES6(3)
开发语言·javascript·es6