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

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:

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:

<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
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值