实现功能:左侧导航高亮,右侧滚动对应左侧导航,左边点击对应右边内容
<template>
<div>
<div class="left">
<div @click="toJump(item.name)" v-for="(item,index) list" :key='index' :class="{ active: activeClass ===item.name }">{{item.name}}</div>
<div>B</div>
</div>
<div class="right">
<div class="item" ref="A" data-myName="A">一楼</div>
<div class="item" ref="B" data-myName="B">二楼</div>
</div>
</div>
</template>
<script>
export default{
data(){
return:{
list:[
{name:'A'},
{name:'B'}
],
activeClass :'A'
}
},
methods:{
toJump(name){
this.$nextTick(() => {
this.$refs[name].scrollIntoView(true);
this.activeClass = name;
this.jumpFlag = true;
});
},
initDom(){
this.$nextTick(() => {
const el = document.querySelector('.right'); // 父元素,其内部元素滚动
const h = el.querySelectorAll('.item');
const offettopList = [];
for (const k of h) {
// 将所有内容的标题以及距离顶部的距离存成一个数组
offettopList.push({ offsetTop: k.offsetTop, name: k.getAttribute('data-myName') });
}
el.addEventListener('scroll', this.handleScroll);
});
},
handleScroll(){
// 点击跳转的时候 滚动事件也会执行(所以点击的时候return)
if (this.jumpFlag) {
this.jumpFlag = false;
return;
}
const el = document.querySelector('.right'); // 父元素,其内部元素滚动
if (!el) return;
this.offsetTopList.forEach((t, i) => {
// +50 是为了让他提前50px的时候导航栏高亮
if (el.scrollTop + 50 >= t.offsetTop) {
this.activeClass = t.name;
}
});
},
// 清除事件
removeScrollFun() {
this.$nextTick(() => {
if (document.querySelector('.form')) {
document.querySelector('.form').removeEventListener('scroll', this.handleScroll);
}
});
}
}
}
</script>
思路:
offsetTop :(参考的对象是)祖先(不一定是父元素,一直往上找)元素、离自己最近、position不为static(static是position的默认值,如果一个元素不设置position,默认是static定位,因此offsetTop所参考的对象的position必须是relative,absolute,fixed中的一个)
scrollTop:获取对象最顶端与对象可见区域最顶端的距离
第一层offsetTop =0
第二层 offsetTop =第一层高度(有一点误差)
滚动的距离的距离大于等于这些的时候让导航栏高亮
this.
n
e
x
t
T
i
c
k
(
c
a
l
l
b
a
c
k
)
,当数据发生变化,更新后执行回调。
t
h
i
s
.
nextTick(callback),当数据发生变化,更新后执行回调。 this.
nextTick(callback),当数据发生变化,更新后执行回调。this.nextTick(callback),当dom发生变化,更新后执行的回调。
加this.$nextTick()是因为,this.activeClass没有变化,应该是因为我在watch中调用这个函数的,此时dom还没有渲染出来,