一个简单的vue锚点跳转demo
拿去直接粘贴就可
<template>
<div class="auto-adjust-edit" >
<!-- 按钮 -->
<div class="operation-btn">
<div class="btn-item" v-for="(item, index) in partList" :key="index" @click="jump(index)"
:style="{background: activeStep === index ? '#eeeeee' : '#ffffff'}">{{item}}
</div>
</div>
<!-- 滚动区域 -->
<div class="scroll-content" @scroll="onScroll">
<div class="scroll-item">
<div class="part-title">基本信息</div>
</div>
<div class="scroll-item">
<div class="part-title">风险控制</div>
</div>
<div class="scroll-item">
<div class="part-title">成本控制</div>
</div>
<div class="scroll-item">
<div class="part-title">量级控制</div>
</div>
<div class="scroll-item">
<div class="part-title">新计划管理</div>
</div>
<div class="scroll-item">
<div class="part-title">老计划管理</div>
</div>
<div class="scroll-item">
<div class="part-title">垃圾计划清理</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
activeStep: 0,
partList: ['基本信息', '风险控制', '成本控制', '量级控制', '新计划管理', '老计划管理', '垃圾计划清理']
}
},
methods: {
// 滚动触发按钮高亮
onScroll (e) {
let scrollItems = document.querySelectorAll('.scroll-item')
for (let i = scrollItems.length - 1; i >= 0; i--) {
// 判断滚动条滚动距离是否大于当前滚动项可滚动距离
let judge = e.target.scrollTop >= scrollItems[i].offsetTop - scrollItems[0].offsetTop - 100;
if (judge) {
this.activeStep = i
break
}
}
},
// 点击切换锚点
jump (index) {
let target = document.querySelector('.scroll-content')
let scrollItems = document.querySelectorAll('.scroll-item')
// 判断滚动条是否滚动到底部
if (target.scrollHeight <= target.scrollTop + target.clientHeight) {
this.activeStep = index
}
let total = scrollItems[index].offsetTop - scrollItems[0].offsetTop // 锚点元素距离其offsetParent(这里是body)顶部的距离(待滚动的距离)
let distance = document.querySelector('.scroll-content').scrollTop // 滚动条距离滚动区域顶部的距离
// let distance = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset // 滚动条距离滚动区域顶部的距离(滚动区域为窗口)
// 滚动动画实现, 使用setTimeout的递归实现平滑滚动,将距离细分为50小段,10ms滚动一次
// 计算每一小段的距离
let step = total / 50
if (total > distance) {
smoothDown(document.querySelector('.scroll-content'))
} else {
let newTotal = distance - total
step = newTotal / 50
smoothUp(document.querySelector('.scroll-content'))
}
// 参数element为滚动区域
function smoothDown (element) {
if (distance < total) {
distance += step
element.scrollTop = distance
setTimeout(smoothDown.bind(this, element), 1)
} else {
element.scrollTop = total
}
}
// 参数element为滚动区域
function smoothUp (element) {
if (distance > total) {
distance -= step
element.scrollTop = distance
setTimeout(smoothUp.bind(this, element), 1)
} else {
element.scrollTop = total
}
}
// document.querySelectorAll('.scroll-item').forEach((item, index1) => {
// if (index === index1) {
// item.scrollIntoView({
// block: 'start',
// behavior: 'smooth'
// })
// }
// })
}
}
}
</script>
<style lang="scss" scoped>
.auto-adjust-edit {
flex-basis: 100%;
display: flex;
overflow: hidden;
height: 500px;
height: 100%;
// 侧边栏
.operation-btn {
width: 9.5%;
height: 95%;
margin-right: 0.5%;
padding-top: 1%;
margin-top: 4px;
background: white;
border: 1px solid rgb(190, 188, 188);
border-radius: 6px;
box-shadow: 0 3px 12px 0 rgba(0, 0, 0, 0.2);
.btn-item {
height: 40px;
line-height: 40px;
padding-left: 20px;
cursor: pointer;
}
}
// 表单内容
.scroll-content {
height: 100%;
width: 90%;
overflow: auto;
.scroll-item {
background: white;
border-radius: 8px;
margin-bottom: 6px;
border: 1px solid rgb(216, 214, 214);
min-height: 300px;
// 标题
.part-title {
height: 40px;
line-height: 40px;
font-weight: 600;
padding-left: 10px;
}
// 表单
/deep/.el-form {
border: 1px solid rgb(190, 189, 189);
width: 98%;
margin: 10px auto 30px;
border-radius: 6px;
/deep/.el-form-item {
margin-bottom: 12px;
margin-top: 10px;
}
}
}
}
}
</style>
Respect to:
https://blog.csdn.net/love__xyy/article/details/88047306?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduend~default-1-88047306.nonecase&utm_term=vue%E9%94%9A%E7%82%B9%E6%8F%92%E4%BB%B6&spm=1000.2123.3001.4430