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