主要思路
- 导航栏固定
判断页面卷曲是否大于导航栏的offsetTop的值,超过了就证明导航栏到达了顶部,给导航栏添加固定样式的类名,注意:需要拿到导航栏固定前的offsetTop值,固定后的offsetTop值为0,会导致页面需要卷曲值为0时,导航栏才复位,中间会有一段突兀的情况。 - 滑动到相应位置导航栏有对应选中样式
遍历锚点元素,当锚点元素占据屏幕显示的2/3区域时,通过排他思想给对应导航添加选中样式 - 点击导航跳转到对应位置
通过scrollIntoView()方法实现锚点跳转,使用方式详见官网。注意:后面需要重新定位卷曲高度,因为导航目前具有fiexd固定头部样式,处于脱标状态,不减去导航栏高度的距离,就会遮挡一部分内容。
html结构
<div class="about">
<div class="banner"><div class="wrap"></div></div>
<!-- 导航 -->
<div class="nav">
<div class="wrap">
<ul>
<li @click="skipTo('#profile')">公司简介</li>
<li @click="skipTo('#development-history')">发展历程</li>
<li @click="skipTo('#enterprise-culture')">企业文化</li>
<li @click="skipTo('#office-location')">办公地点</li>
</ul>
</div>
</div>
<!-- 锚点元素 -->
<div class="about-content">
<div id="profile">公司简介</div>
<div id="development-history">发展历程</div>
<div id="enterprise-culture">企业文化</div>
<div id="office-location">办公地点</div>
</div>
</div>
js代码
export default {
data () {
return {
navOffsetTop: 0
}
},
mounted () {
// 监听滚动事件
window.addEventListener('scroll', this.fiexdNav)
this.getData()
},
destroyed () {
// 必须移除监听器,不然当该vue组件被销毁了,监听器还在就会出错
window.removeEventListener('scroll', this.fiexdNav)
},
methods: {
/** 设置导航条nav到达页面顶部时固定 **/
// 1.获取导航条nav的offsetTop值,存储在data中(注:之所以不放在滚动事件中,是为了以防添加固定样式后offsetTop值为零,导致页面需要滚动到最上面才可以回到原位)
getData () {
this.navOffsetTop = document.querySelector('.nav').offsetTop
},
fiexdNav () {
// 2.获取当前页面的卷曲高度
const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
const nav = document.querySelector('.nav')
// 3.判断卷曲高度是否大于等于导航条的offsetTop值
if (scrollTop > this.navOffsetTop) {
// 3.1若满足,则给nav导航添加固定样式
nav.classList.add('fixedNav')
} else {
// 3.2若不满足,则删除nav导航的固定样式
nav.classList.remove('fixedNav')
}
/** 当滚动到一定区域时给导航项添加选中样式 **/
// 1.获取所有锚点元素
const contents = document.querySelectorAll('.about-content>div')
// 2.获取锚点元素的offsetTop值,并收集在一个数组
const contentsOffsetTop = []
contents.forEach(item => {
contentsOffsetTop.push(item.offsetTop)
})
// 3.获取页面高度
const pageHeight = window.innerHeight
// 4.获取nav的子元素
const navChildren = document.querySelectorAll('.nav li')
// 5.遍历锚点元素的offsetTop值
for (let i = 0; i < contentsOffsetTop.length; i++) {
// 5.1 设置第一项导航默认为选中状态
if (i === 0) {
navChildren[0].classList.add('active')
} else if (scrollTop > contentsOffsetTop[i - 1] + pageHeight / 3) {
// 排他思想
for (let j = 0; j < contentsOffsetTop.length; j++) {
navChildren[j].classList.remove('active')
navChildren[i].classList.add('active')
}
} else {
navChildren[i].classList.remove('active')
}
}
},
/**
*设置点击导航跳转到指定选择器对应的锚点元素
* @param {*} selector
**/
skipTo (selector) {
const navHeight = document.querySelector('.nav').offsetHeight
// scrollIntoView() js原生方法,实现锚点滚动过渡
const target = document.querySelector(selector)
target.scrollIntoView({ behavior: 'smooth' })
// scrollTo() 把内容滚动到指定的坐标。减去导航高度的目的:导航用定位固定在顶部,如果不减去,导航栏会遮挡一部分内容
window.scrollTo(0, target.offsetTop - navHeight)
}
}
}
css样式
css代码只放了功能中用到的
.fixedNav {
position: fixed;
width: 100%;
top: 0;
left: 0;
z-index: 100;
}
.active {
color: @main_green_color;
border-bottom: 2px solid @main_green_color;
}