主要思路

  • 导航栏固定
    判断页面卷曲是否大于导航栏的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;
    }
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐