思路:是通过监听页面的滚动事件,根据当前滚动位置计算对应的小圆点,并给该小圆点添加 active
类来实现小圆点导航的联动效果。同时,在点击小圆点时,通过滚动到对应的位置来实现页面滚动。
实现步骤:
- 在 Vue 组件中添加
scroll
事件监听器,并在对应的回调函数中处理滚动事件; - 遍历每个小圆点的位置,判断滚动位置是否在当前小圆点对应的区域内,如果是,则将
currentSection
设置为对应的索引值; - 在小圆点中添加
v-for
指令和@click
事件监听器,用于点击小圆点时触发页面滚动,并更新currentSection
的值; - 在小圆点的
class
属性中添加{'active': index === currentSection}
表达式,表示当前小圆点是否处于激活状态; - 使用
scrollIntoView
方法实现页面滚动,并通过 setTimeout 函数设置一个延时任务,一段时间后将导航标志位重置为false
。
<div class="box">
//小导航
<div class="navigation">
<ul>
<li class="dot"
v-for="(item, index) in sections"
:key="index"
@click="scrollToSection(index)"
:class="{'active': index === currentSection}"></li>
</ul>
</div>
//内容区域
<div class='conent'>
<div id="box-one" class="box-one"></div>
<div id="box-two" class="box-one"></div>
<div id="box-three" class="box-one"></div>
</div>
</div>
<style lang="scss" scoped>
.box{
.navigation{
position: fixed; //固定导航位置
top: 50%;
right: 20px;
transform: translateY(-50%);
z-index: 999;
text-align: center;
ul{
.dot{
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #989898;
margin-bottom: 20px;
cursor: pointer;
position: relative;
&.active{ //点击或者滑动后的样式
width: 12px;
height: 12px;
&::before{
content: '';
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
width: 6px;
height: 6px;
border-radius: 50%;
background-color: #fff;
}
}
&:not(:last-child)::after{ //除了最后一个小圆点添加连线
content: '';
position: absolute;
top: 100%;
width: 2px;
height: 200%;
background-color: #cacaca;
}
}
}
}
.content{
//内容部分样式
}
}
通过HTML和CSS部分固定导航位置和样式,通过JavaScript实现功能
<script>
export default {
data(){
return {
sections:['box-one','box-two','box-three','box-four','box-five','box-six','box-seven',],
currentSection:0,
isNavigating:false, //添加标志位
}
},
mounted(){
// 鼠标滚动监听器
window.addEventListener('scroll',this.handleScroll)
},
beforeDestroy(){
window.removeEventListener('scroll',this.handleScroll)
},
methods:{
// 小圆点导航
scrollToSection(index){
if(this.isNavigating) return; //如果正在导航,则不执行后续代码
this.currentSection = index
const sectionId = this.sections[index]
const element = document.getElementById(sectionId)
element.scrollIntoView({behavior:'smooth'})
this.isNavigating = true //设置导航标志位為TRUE
setTimeout(()=>{
this.isNavigating = false //一段时间后重置导航标志位為FALSE
},1000)
},
// 处理鼠标滚动事件
handleScroll(){
if(this.isNavigating) return; //如果正在导航,则不执行后续代码
// 获取窗口高度
const windowHeight = window.innerHeight
// 获取当前滚动位置
const scrollPosition = window.pageYOffset || document.documentElement.scrollTo
// 遍历每个小圆点的位置
this.sections.forEach((sectionId,index) => {
const element = document.getElementById(sectionId)
if(element){
const elementTop = element.offsetTop
// 判断滚动位置是否在当前小圆点对应的区域内
if(scrollPosition >= elementTop - windowHeight / 2 && scrollPosition < elementTop + element.offsetHeight){
this.currentSection = index
}
}
});
},
},
}
</script>
1.添加了 scrollToSection()方法来处理点击事件
2. 添加了 handleScroll
方法来处理滚动事件。首先,通过 window.innerHeight
获取窗口的高度,而 window.pageYOffset || document.documentElement.scrollTop
获取当前的滚动位置。
接下来,遍历每个小圆点的位置(通过 sections
数组),获取对应 DOM 元素的 offsetTop
。然后,判断滚动位置是否在当前小圆点对应的区域内(通过与窗口高度进行比较),如果是,则将 currentSection
设置为对应的索引值。
最后,在组件的生命周期钩子函数中添加对 scroll
事件的监听,并在组件销毁前移除该监听。
2. 添加了 isNavigating
属性来表示是否正在进行导航动画。在点击小圆点时,首先检查 isNavigating
的值,如果为 true
,则直接返回,不执行后续代码;否则,将 isNavigating
设置为 true
,执行滚动操作,并通过 setTimeout 函数设置一个延时任务,一段时间后将 isNavigating
重置为 false
。
这样,在导航过程中,只有第一次点击小圆点时会触发滚动和重新渲染,后续的滚动事件不会触发 handleScroll
方法,从而避免了小圆点样式的闪烁问题。