Home/Article/website/nuxt3 setup ts 实现锚点跳转及滚动监听好用例子
nuxt3
<template>
<div>
<!-- 内容区域 -->
<div class="content">
<div>content-0</div>
<div>content-1</div>
<div>content-2</div>
<div>content-3</div>
<div>content-4</div>
</div>
<!-- 导航区域 -->
<ul class="navs">
<li :class="{ active: active === 0 }" @click="scrollTo(0)">content-0</li>
<li :class="{ active: active === 1 }" @click="scrollTo(1)">content-1</li>
<li :class="{ active: active === 2 }" @click="scrollTo(2)">content-2</li>
<li :class="{ active: active === 3 }" @click="scrollTo(3)">content-3</li>
<li :class="{ active: active === 4 }" @click="scrollTo(4)">content-4</li>
</ul>
</div>
</template>
<script>
export default {
props: {},
data() {
return {
active: 0, // 当前激活的导航索引
};
},
mounted() {
// 监听滚动事件
window.addEventListener("scroll", this.onScroll, false);
},
destroy() {
// 必须移除监听器,不然当该vue组件被销毁了,监听器还在就会出错
window.removeEventListener("scroll", this.onScroll);
},
methods: {
// 滚动监听器
onScroll() {
// 获取所有锚点元素
const navContents = document.querySelectorAll(".content div");
// 所有锚点元素的 offsetTop
const offsetTopArr = [];
navContents.forEach((item) => {
offsetTopArr.push(item.offsetTop);
});
// 获取当前文档流的 scrollTop
const scrollTop =
document.documentElement.scrollTop || document.body.scrollTop;
// 定义当前点亮的导航下标
let navIndex = 0;
for (let n = 0; n < offsetTopArr.length; n++) {
// 如果 scrollTop 大于等于第n个元素的 offsetTop 则说明 n-1 的内容已经完全不可见
// 那么此时导航索引就应该是n了
if (scrollTop >= offsetTopArr[n]) {
navIndex = n;
}
if (
scrollTop + document.documentElement.clientHeight ===
document.documentElement.scrollHeight
) {
navIndex = offsetTopArr.length - 1;
}
}
this.active = navIndex;
},
// 跳转到指定索引的元素
scrollTo(index) {
// 获取目标的 offsetTop
// css选择器是从 1 开始计数,我们是从 0 开始,所以要 +1
const targetOffsetTop = document.querySelector(
`.content div:nth-child(${index + 1})`
).offsetTop;
// 获取当前 offsetTop
let scrollTop =
document.documentElement.scrollTop || document.body.scrollTop;
// 定义一次跳 50 个像素,数字越大跳得越快,但是会有掉帧得感觉,步子迈大了会扯到蛋
const STEP = 50;
// 判断是往下滑还是往上滑
if (scrollTop > targetOffsetTop) {
// 往上滑
smoothUp();
} else {
// 往下滑
smoothDown();
}
// 定义往下滑函数
function smoothDown() {
// 如果当前 scrollTop 小于 targetOffsetTop 说明视口还没滑到指定位置
if (scrollTop < targetOffsetTop) {
// 如果和目标相差距离大于等于 STEP 就跳 STEP
// 否则直接跳到目标点,目标是为了防止跳过了。
if (targetOffsetTop - scrollTop >= STEP) {
scrollTop += STEP;
} else {
scrollTop = targetOffsetTop;
}
document.body.scrollTop = scrollTop;
document.documentElement.scrollTop = scrollTop;
// 关于 requestAnimationFrame 可以自己查一下,在这种场景下,相比 setInterval 性价比更高
requestAnimationFrame(smoothDown);
}
}
// 定义往上滑函数
function smoothUp() {
if (scrollTop > targetOffsetTop) {
if (scrollTop - targetOffsetTop >= STEP) {
scrollTop -= STEP;
} else {
scrollTop = targetOffsetTop;
}
document.body.scrollTop = scrollTop;
document.documentElement.scrollTop = scrollTop;
requestAnimationFrame(smoothUp);
}
}
},
},
};
</script>
<style scoped>
/* 内容区的样式 */
.content {
background-color: white;
width: 500px;
}
.content div {
width: 100%;
height: 600px;
font-size: 36px;
padding: 20px;
background-color: #7ec384;
}
.content div:nth-child(2n) {
background-color: #847ec3;
}
/* 导航栏的样式 */
.navs {
position: fixed;
top: 80px;
left: 700px;
background-color: #efefef;
}
.navs li {
padding: 0 20px;
line-height: 1.6;
font-size: 24px;
}
/* 当导航被点亮后改变颜色 */
.navs .active {
color: #847ec3;
background-color: #e2e2e2;
}
</style>
上一篇: nuxt3 分类名嵌套分类下内容的循环例子下一篇: nuxt3 setup ts 实现锚点跳转及滚动监听最简例子