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

相关推荐
勉灬之几秒前
Next.js + Prisma 跨平台部署踩坑记
开发语言·javascript·ecmascript
cll_8692418911 分钟前
一个好看的Wordpress博客文字css样式
前端·css·ui
糖果店的幽灵5 分钟前
langgraph分支之 - 动态分支(Dynamic Branch)
java·前端·javascript·人工智能·langgraph
meilindehuzi_a16 分钟前
Workflow 与 Agent 有什么区别:从 LangChain 流水线到智能体决策
前端·人工智能
Bad_Shepherd21 分钟前
vue-element-plus-admin添加自定义svg图标,并且图标选择组件可选自定义图标
vue.js·elementui·前端框架
这是个栗子24 分钟前
前端开发中的常用工具函数(九)
开发语言·javascript·ecmascript·at
吃糖的小孩2 小时前
从只读页面到可控真实探针:我如何给 Owner Console 加手动诊断
前端
谷无姜2 小时前
为什么你的性能优化无效?可能是"木桶效应"在作祟
前端·性能优化
雾非雾2 小时前
《基于具身交互智能数字人技术:如何打造AI数字人宣讲平台"红厅智播”》
前端
Revolution612 小时前
一段 JavaScript 代码执行时,到底发生了什么
前端·javascript