效果

实现
<template>
<div class="home">
<div class="box">
<div class="left">
<div class="title" :class="index === 0 ? 'index' : ''" @click="titleClick(0)">0</div>
<div class="title" :class="index === 1 ? 'index' : ''" @click="titleClick(1)">1</div>
<div class="title" :class="index === 2 ? 'index' : ''" @click="titleClick(2)">2</div>
<div class="title" :class="index === 3 ? 'index' : ''" @click="titleClick(3)">3</div>
<div class="title" :class="index === 4 ? 'index' : ''" @click="titleClick(4)">4</div>
<div class="title" :class="index === 5 ? 'index' : ''" @click="titleClick(5)">5</div>
</div>
<div class="right">
<div class="content" style="height:200px; background-color: rgb(225, 0, 100);">0</div>
<div class="content" style="height:800px; background-color: rgb(0, 0, 0);">1</div>
<div class="content" style="height:500px; background-color: rgb(225, 0, 20);">2</div>
<div class="content" style="height:1000px; background-color: rgb(225, 171, 0);">3</div>
<div class="content" style="height:700px; background-color: rgb(221, 200, 20);">4</div>
<div class="content" style="height:400px; background-color: rgb(150, 0, 150);">5</div>
</div>
</div>
</div>
</template>
<script>
import _ from 'lodash'
export default {
data() {
return {
time: undefined,
timeout: undefined,
index: 0,
rightDiv: undefined,
content: undefined
}
},
mounted() {
this.rightDiv = document.querySelector('.right')
this.content = document.querySelectorAll('.content')
this.time = _.throttle(this.rightScroll, 100)
this.rightDiv.addEventListener('scroll', this.time)
},
destroyed() {
clearTimeout(this.timeout)
this.time.cancel()
},
methods: {
rightScroll() {
for (let i = 0; i < this.content.length; i++) {
if (this.content[i].offsetTop <= this.rightDiv.scrollTop) {
this.index = i
}
}
if (this.rightDiv.scrollTop + this.rightDiv.clientHeight === this.rightDiv.scrollHeight) {
this.index = this.content.length - 1
}
},
titleClick(index) {
clearTimeout(this.timeout)
this.index = index
this.rightDiv.removeEventListener('scroll', this.time)
this.scrollToElem(this.content[index], 500)
this.timeout = setTimeout(() => {
this.rightDiv.addEventListener('scroll', this.time)
}, 600)
},
scrollToElem(elem, duration) {
const startingY = this.rightDiv.scrollTop
const diff = elem.offsetTop - startingY
if (!diff) return
const that = this
const easing = x => 1 - Math.pow(1 - x, 4)
let start
window.requestAnimationFrame(function step(timestamp) {
if (!start) start = timestamp
const time = timestamp - start
let percent = Math.min(time / duration, 1)
percent = easing(percent)
that.rightDiv.scrollTo(0, startingY + diff * percent)
if (time < duration) {
window.requestAnimationFrame(step)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.home {
display: flex;
justify-content: center;
padding: 20px;
}
.box {
width: 1000px;
height: 800px;
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
display: flex;
overflow: hidden;
.left {
width: 30%;
.title {
width: 100%;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid;
}
.index {
background-color: aqua;
}
}
.right {
width: 70%;
position: relative;
overflow-y: auto;
.content {
width: 100%;
height: 400px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
background-color: rgb(221, 20, 20);
}
}
}
</style>