可根据左侧导航点击,定位右侧内容
也可根据右侧内容滚动位置,定位左侧导航
具体代码
<template>
<div>
<div class="headContent">
<span class="headContentLeft">左侧导航</span>
<span class="headContentRight">右侧内容</span>
</div>
<div class="content" ref="parentContent">
<div class="content-left">
<div v-for="item in data" :key="item.id" :class="['content-left-item',activeId===item.id?'activeNav':'']" :ref="'nav'+item.id" @click="goNavItem(item.id)">
{{item.name}}
</div>
</div>
<div class="content-right" ref="rightContent">
<div v-for="item in data" :key="item.id" :class="['content-right-item',activeId===item.id?'activeNav':'']" :ref="'item'+item.id" :style="{height:item.height}">
{{item.text}}
</div>
</div>
</div>
<div class="buttonContent">
底部
</div>
</div>
</template>
<script>
export default {
data(){
return{
data:[
{id:'1',name:'行一',text:'我是第一行',height:'100px'},
{id:'2',name:'行二',text:'我是第二行',height:'200px'},
{id:'3',name:'行三',text:'我是第三行',height:'300px'},
{id:'4',name:'行四',text:'我是第四行',height:'400px'},
{id:'5',name:'行五',text:'我是第五行',height:'500px'},
{id:'6',name:'行六',text:'我是第六行',height:'600px'},
],
activeId:'',
}
},
created(){
if(this.data.length>0){
this.activeId = this.data[0].id
}
},
mounted(){
this.addScrollListener() //添加监听
},
beforeDestroy () {
// 移除监听
window.removeEventListener('click', ()=>{
this.activeId ='1'
})
},
methods:{
// 点击左侧导航时,右侧对应内容进行滚动定位
goNavItem(id){
this.activeId = id
let element = this.$refs['item'+id]
if(element){
let itemElement = element[0]?element[0]:element
itemElement.scrollIntoView() //滚动到itemElement元素顶部
}
},
// 滚动时,获取右侧元素的滚动信息
getElementInfo(){
var scrollActiveId = null
// 获取父元素到可视窗口的位置
let parentElement = this.$refs.parentContent
let parentTop = parentElement.getBoundingClientRect().top
this.data.forEach(item=>{
let element = this.$refs['item'+item.id]
if(element){
let itemElement = element[0]?element[0]:element
// 可以获取到itemElement元素的具体高度,宽度,距离可视窗口的位置信息
let scrollInfo = itemElement.getBoundingClientRect()
//当前元素到父元素的距离
let curTop = scrollInfo.top - parentTop
// scrollInfo.top为具体元素到可视窗口的位置, 如果元素顶部的一半在父元素中,则设置定位该元素
if(!scrollActiveId){
if(scrollInfo.top > 0 && curTop < (scrollInfo.height / 2)){
scrollActiveId = item.id
}
}
}
})
return scrollActiveId
},
// 滚动监听,进行定位
addScrollListener(){
let rightElement = this.$refs.rightContent
if(rightElement){
rightElement.addEventListener('scroll',()=>{
let scrollActiveId = this.getElementInfo()
if(scrollActiveId){
this.activeId =scrollActiveId
}
})
}
}
}
}
</script>
<style lang="less" scoped>
.headContent{
width: 100%;
height: 50px;
line-height: 50px;
font-size: 20px;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #fff;
span {
background-color: #ecf5ff;
}
}
.headContentLeft{
width: 100px;
margin-right: 20px;
border-radius: 4px;
}
.headContentRight{
flex: 1;
border-radius: 4px;
}
.buttonContent{
width: 100%;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
background-color: #ecf5ff;
margin-top: 10px;
}
.content{
display: flex;
padding-top: 20px;
}
.content-left{
margin-right: 20px;
}
.content-left-item{
width: 100px;
height: 40px;
line-height: 40px;
background-color: #e1f3d8;
margin-bottom: 10px;
border-radius: 4px;
cursor: pointer;
}
.content-right{
flex: 1;
height: calc( 100vh - 150px);
overflow-y: scroll;
border: 1px solid #b5c8df;
padding: 20px;
box-sizing: border-box;
border-radius: 4px;
}
.content-right-item{
width: 100%;
border: 1px solid #eae6e6;
border-radius: 4px;
margin-bottom: 20px;
box-sizing: border-box;
font-size: 25px;
display: flex;
justify-content: center;
align-items: center;
}
.activeNav{
background-color: #67c23a;
color: #fff;
}
</style>