在项目中需要实现左侧为tab栏,右侧对应页面滚动实时刷新tab,且可根据点击tab定位锚点的功能
1. scrollTop、offsetTop属性
主要涉及到两个属性scrollTop和offsetTop;
scrollTop属性定义如下:
一个元素的 scrollTop 值是这个元素的顶部到
视口可见内容
(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0。
offsetTop属性定义如下:
HTMLElement.offsetTop
为只读属性,它返回当前元素相对于其offsetParent
元素的顶部内边距的距离。
其中offsetParent定义为与当前元素最近的经过定位( position 不等于 static )的父级元素,具体情况如下
- position为fixed时,offsetParent为null,offsettop的值和top相等。此时元素是以视口来定位的。
- position非fixed,父级元素无定位(static)时,offsetParent为body。
- position非fixed,父级元素有定位时,offsetParent为最近的有定位的父级元素。
- body元素,offsetParent为null,offsettop为0。
2. 当前页面和实现方案介绍
这里的页面为左侧tab栏,右侧内容滚动区域。
<div class="main">
<!-- tab区域,需要设置activeKey -->
<div class="tabs">
<ul>
<li
v-for="item in tabList"
:key="item.key"
:class="{active: activeKey === item.key}"
@click="goAnchor(item.key)"
>{{ item.title }}</li>
</ul>
</div>
<!-- .content需要加上position: relative样式从而使得内部五个div的offsetTop为到.content元素顶部的距离 -->
<div class="content">
<!-- 五个div需要赋高度 -->
<div class="scrollContent one" />
<div class="scrollContent two" />
<div class="scrollContent three" />
<div class="scrollContent four" />
<div class="scrollContent five" />
</div>
</div>
<style lang="scss" scoped>
.content {
position: relative;
overflow-y: scroll;
}
</style>
我们可以得到五个子div相对于.content的offsetTop,与.content的scrollTop属性进行比较即可获得当前视口为哪个子div区域,从而更新activeKey显示对应的tab,这就是整体的实现思路。
3. tab栏根据页面滚动实时更新
下面看代码实现
onScroll() {
// 获取每个子div的offsetTop
const offsetTopArr = [];
const anchors = document.querySelector(".scrollContent");
anchors.forEach(i => { offsetTopArr.push(i.offsetTop) });
// 获取当前.content区域的scrollTop
const content = document.querySelector(".content");
const scrollTop = content.scrollTop;
// 比较得出当前在第几个子div
let curIndex = 0;
for (let i = 0; i < offsetTopArr.length; i++) {
if (scorllTop >= offsetTopArr[i]) {
curIndex = i;
}
}
this.activeKey = this.tabList[curIndex].key;
}
实时更新的情况需要加入监听页面滚动事件
mounted() {
window.addEventListener("scroll", this.onScroll, true);
},
destoryed() {
window.removeEventListener("scroll", this.onScroll);
},
或是给.content元素绑定scroll事件
<div class="content" @scroll="onScroll">
4. 定位锚点
理解了上面步骤2、3的思路再去实现定位锚点功能就轻而易举了
将当前.content的scrollTop改为tab对应子div的offsetTop,视口则会定位到对应的子div
goAnchor(key) {
this.activeKey = key;
const className = "." + key;
const anchor = this.$el.querySelector(className);
const content = document.querySelector(".content");
content.scrollTop = anchor.offsetTop;
}