效果
实现
css 使用了 unocss
使界面滚动到给定元素的指定坐标位置
window.scrollTo({ top: 0 })
使用了内边距避免最后数据高度不够
<main class="pb-100vh"></main>
完整代码
<script lang="ts" setup>
defineOptions({ name: 'DemoView' })
/** dom */
const itemRefs = ref<HTMLElement[]>([])
/** 导航列表数据 */
const navList = ['导航一', '导航二', '导航三', '导航四', '导航五']
/** 导航的索引 */
const activeIndex = ref(0)
/**
* 切换导航
* @param index 点击的索引
*/
function handleNav(index: number) {
activeIndex.value = index
scrollTo({ top: itemRefs.value[index]?.offsetTop })
}
/**
* 监听滚动方法
*/
function onScroll() {
const offsetTopArr: number[] = []
itemRefs.value?.forEach((item) => {
offsetTopArr.push((item as HTMLElement)?.offsetTop)
})
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
}
}
activeIndex.value = navIndex
}
onMounted(() => {
window.addEventListener('scroll', onScroll, false)
})
onUnmounted(() => {
window.removeEventListener('scroll', onScroll)
})
/**
* 封装滚动到指定位置的方法
* @param param0
*/
function scrollTo({
top = 0,
behavior = 'smooth'
}: {
top?: number | undefined
behavior?: ScrollBehavior
}) {
window.scrollTo({
top,
behavior
})
}
</script>
<template>
<div class="pl-150px">
<nav class="fixed left-0px top-80px">
<ul>
<template v-for="(nav, index) of navList" :key="index">
<li
class="py-30px text-[#666] cursor-pointer"
:class="{ active: activeIndex === index }"
@click="handleNav(index)"
>
{{ nav }}
</li>
</template>
</ul>
</nav>
<main class="pb-100vh">
<template v-for="(nav, index) of navList" :key="index">
<div ref="itemRefs" class="h-200px w-200px mb-20px pb-30px bg-blue-700 text-white">
{{ nav }}
</div>
</template>
</main>
</div>
</template>
<style lang="scss" scoped>
li {
list-style: none;
}
.active {
@apply text-blue-700 font-bold;
}
</style>