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

相关推荐
云水一下4 分钟前
TypeScript 从零基础到精通(二):基础类型与类型系统
javascript·typescript
你怎么知道我是队长22 分钟前
CRC校验C语言实现-CRC8、CRC16、CRC16的直接计算法、查表法
c语言·前端·javascript
Rain50939 分钟前
mini-cc 终端 UI:用 React 写 CLI 是什么体验
前端·人工智能·react.js·ui·架构·前端框架·ai编程
wu85877345744 分钟前
向量数据库不是银弹:从枚举漏检到 ReACT 多轮召回的实践路径
前端·数据库·react.js
meilindehuzi_a1 小时前
深入理解 JavaScript 执行机制:从编译阶段到调用栈底层实现
开发语言·javascript·ecmascript
古怪今人1 小时前
[前端]HTML盒模型与尺寸,标准文档流,块级元素、内联元素和行内块,CSS选择器
前端·css
小雨下雨的雨1 小时前
基于鸿蒙PC Electron框架技术完成的表单验证技术详解
前端·javascript·华为·electron·前端框架·鸿蒙
提子拌饭1331 小时前
饮料含糖量查询应用 - 鸿蒙PC用Electron框架完整实现
前端·javascript·华为·electron·前端框架·鸿蒙
JustHappy1 小时前
古法编程秘籍(五):什么是进程和线程?从软件到 CPU 的一次完整旅程
前端·后端·代码规范
爱编程的小金1 小时前
前端请求库的下一个进化方向:从 Promise 到策略化
前端·alova·前端请求库·请求策略