最近有个需求:导航目录跟内容联动,发现网上相关内容比较少,我就花了点时间总结一下,先看效果
样式优点丑,这个不纠结,咱们主要看功能
样式
这里主要有右侧目录导航栏和内容样式,样式混入的知识点,请看文章
<template>
<div class="container" ref="container">
<div ref="boxs" class="box" v-for="c in colors" :key="c" :id="c" :style="{background: c}">
<h2>{{c}}</h2>
</div>
<div class="directory">
<p v-for="c in colors" :key="c" :style="{background: (currentItem === c && c) || 'black'}">{{ c }}</p>
</div>
</div>
</template>
<script lang="ts" setup>
const colors = ['red', 'green', 'blue', 'yellow', 'skyblue', 'purple', 'brown', 'pink']
const currentItem = ref('red')
const container = ref<HTMLDivElement | null>(null)
const boxs = ref<HTMLDivElement[] | null>([])
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 100%;
position: relative;
// @include overflow-overlay(); // 这@include是混入等价代码下面两行
overflow: auto;
overflow: overlay;
// scroll-behavior: smooth;
.box {
width: 100%;
height: 600px;
}
.directory {
background-color: #eee;
border: 1px solid #fff;
position: fixed;
right: 0;
top: 50%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
padding: 4px;
color: white;
border-radius: 4px;
> p {
width: 100%;
height: 24px;
line-height: 24px;
padding: 0 4px;
border-radius: 4px;
text-align: center;
cursor: pointer;
}
}
}
</style>
目录导航 => 内容联动
给目录导航注册点击事件,通过scrollIntoView
方法使得内容到指定位置
- 点击导航高亮自己
- 找到导航对应的定位的元素
- 将元素置顶
<template>
<div class="container" ref="container">
<div ref="boxs" class="box" v-for="c in colors" :key="c" :id="c" :style="{background: c}">
<h2>{{c}}</h2>
</div>
<div class="directory">
<p @click="scrollToItem(c)" v-for="c in colors" :key="c" :style="{background: (currentItem === c && c) || 'black'}">{{ c }}</p>
</div>
</div>
</template>
<script lang="ts" setup>
const colors = ['red', 'green', 'blue', 'yellow', 'skyblue', 'purple', 'brown', 'pink']
const currentItem = ref('red')
const scrollToItem = (item: string) => {
// 1. 点击导航高亮自己
currentItem.value = item
// 2. 找到导航对应的定位的元素
const element: HTMLElement | null = document.getElementById(item)
// 3. 将元素置顶
element?.scrollIntoView()
}
</script>
内容 =>目录导航联动
通过注册scroll
事件计算container
的scrollTop
跟每个内容的offsetTop
比较设置currentItem
,关于scrollTop
、offsetTop
,请看文章
- 注册滚动事件
- 销毁滚动事件
- 拿到container滚动卷曲的高度scrollTop
- 如果container的scrollTop >= 滚动的元素的offsetTop,代表该元素到达顶部,这个时候高亮导航栏
<script lang="ts" setup>
const colors = ['red', 'green', 'blue', 'yellow', 'skyblue', 'purple', 'brown', 'pink']
const currentItem = ref(colors[0])
const scrollToItem = (item: string) => {
// 1. 点击导航高亮自己
currentItem.value = item
// 2. 找到导航对应的定位的元素
const element: HTMLElement | null = document.getElementById(item)
// 3. 将元素置顶
element?.scrollIntoView()
}
const container = ref<HTMLDivElement | null>(null)
onMounted(() => {
// 1. 注册滚动事件
container.value?.addEventListener('scroll', onScroll)
})
onBeforeUnmount(() => {
// 2. 销毁滚动事件
container.value?.removeEventListener('scroll', onScroll)
})
const boxs = ref<HTMLDivElement[] | null>([])
const onScroll = () => {
// 3. 拿到container滚动卷曲的高度scrollTop
const scrollTop = container.value?.scrollTop || 0
boxs.value?.forEach(v => {
// 4. 如果container的scrollTop >= 滚动的元素的offsetTop,代表该元素到达顶部,这个时候高亮导航栏
if (scrollTop >= v.offsetTop) {
currentItem.value = v.id
}
})
}
</script>