需求:
- el-tabs列表项,点击标题自动锚定到对应的内容区域
- 内容滚动到对应区域时,自动定位到对应标题,并高亮
实现:
<el-tabs v-model="tabName" class="home-tabs" @tab-click="jump">
<template v-for="(tab, index) of tabs">
<el-tab-pane :key="index" :label="tab.title" :name="tab.refName"></el-tab-pane>
</template>
</el-tabs>
<div
class="content scroll-content"
@scroll="onScroll"
:style="'overflow-x: hidden; overflow-y: auto;height:' + contentStyleObj.height"
>
<div :ref="tabs[0].refName" class="scroll-item">
<p>基本信息</p>
......
</div>
<div :ref="tabs[1].refName" class="scroll-item">
<p>客户信息</p>
......
</div>
<div :ref="tabs[2].refName" class="scroll-item">
<p>企业信息</p>
......
</div>
<div :ref="tabs[3].refName" class="scroll-item">
<p>联系人信息</p>
......
</div>
......
</div>
export default {
data() {
return {
activeTab: "1",
tabIndex: "0",
tabName: "basic",
tabs: [
{ title: "基本信息", refName: "basic" },
{ title: "客户信息", refName: "customer" },
{ title: "企业信息", refName: "business" },
{ title: "联系人信息", refName: "contact" },
],
contentStyleObj: {
height: "100px"
},
scrollItems: [],
isScroll: true
};
},
created() {
this.getHight();
window.addEventListener("resize", this.getHight);
},
mounted() {
this.scrollItems = document.querySelectorAll(".scroll-item");
},
destroyed() {
window.removeEventListener("resize", this.getHight);
},
methods: {
jump(tab, event) {
this.isScroll = false;
let target = document.querySelector(".scroll-content");
if (target.scrollHeight <= target.scrollTop + target.clientHeight) {
this.tabIndex = tab.index.toString();
}
let totalY = this.scrollItems[tab.index].offsetTop - this.scrollItems[0].offsetTop;
let distance = document.querySelector(".scroll-content").scrollTop;
let step = totalY / 50;
if (totalY > distance) {
smoothDown(document.querySelector(".scroll-content"));
} else {
let newTotal = distance - totalY;
step = newTotal / 50;
smoothUp(document.querySelector(".scroll-content"));
}
function smoothDown(element) {
if (distance < totalY) {
distance += step;
element.scrollTop = distance;
setTimeout(smoothDown.bind(this, element), 10);
} else {
element.scrollTop = totalY;
}
}
function smoothUp(element) {
if (distance > totalY) {
distance -= step;
element.scrollTop = distance;
setTimeout(smoothUp.bind(this, element), 10);
} else {
element.scrollTop = totalY;
}
}
setTimeout(() => {
this.isScroll = true;
}, 500);
},
onScroll(e) {
if (!this.isScroll) return;
const scrollTop = e.target.scrollTop;
let foundIndex = -1;
for (let i = 0; i < this.scrollItems.length; i++) {
const item = this.scrollItems[i];
const threshold = item.offsetTop - this.scrollItems[0].offsetTop - 100;
if (scrollTop >= threshold) {
foundIndex = i;
} else {
break;
}
}
if (foundIndex !== -1) {
this.tabIndex = foundIndex.toString();
this.tabName = this.tabs[this.tabIndex].refName;
}
},
getHight() {
this.contentStyleObj.height = window.innerHeight - 175 + "px";
}
}
};