页面锚点滚动导航【详细版】

<template>
  <div>
    <ul class="louplus-nav">
      <li
        v-for="(item, index) in nav"
        :key="index"
        :class="{'active':activeKey === item.key}"
        @click="roll(item.key)"
      >
        <span>
          {{ item.value }}
        </span>
      </li>
      <li v-if="nav.length">
        <a href="#">
          <i class="fa fa-chevron-up" />
        </a>
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  data() {
    return {
      nav: [],
      nodeList: [],
      activeKey: '',
      timer: 0,
    }
  },
  mounted() {
    this.initNav()
    this.initNodeList()
    window.addEventListener('scroll', this.listenScroll)
  },
  destroyed() {
    window.removeEventListener('scroll', this.listenScroll)
  },
  methods: {
    // 初始化定位按钮元素
    initNav() {
      switch (this.$route.name) {
        case 'louplus-python':
          this.nav = this.$LouplusLandEnum.pythonNav
          break
        case 'louplus-ml':
          this.nav = this.$LouplusLandEnum.mlNav
          break
        case 'louplus-dm':
          this.nav = this.$LouplusLandEnum.dmNav
          break
        case 'louplus-bigdata':
          this.nav = this.$LouplusLandEnum.bigdataNav
          break
        case 'louplus-linux':
          this.nav = this.$LouplusLandEnum.linuxNav
      }
    },
    // 初始化定位目标元素
    initNodeList() {
      for (let i = 0; i < this.nav.length; i++) {
        const node = document.querySelector(`.louplus-${this.nav[i].key}`)
        this.nodeList.push({
          key: this.nav[i].key,
          node,
        })
      }
    },
    roll(key) {
      this.activeKey = key
      // 获取目标区域元素
      const node = document.querySelector(`.louplus-${key}`)
      // 获取当前区域的位置
      const windowScrollHeight = document.documentElement.scrollTop
      // 获取目标区域相对于当前窗口的位置
      const nodeOffsetTop = node.getClientRects()[0].top
      // 滚动到相应位置(目标区域位置)
      document.documentElement.scrollTop =
        windowScrollHeight + nodeOffsetTop - 120
    },
    // 屏幕滚动事件回调
    listenScroll() {
      if (this.timer) {
        return
      }
      // 设置延时器,保证100ms最多执行一次
      this.timer = setTimeout(() => {
        for (let i = 0; i < this.nodeList.length; i++) {
          const item = this.nodeList[i]
          const nodeOffsetTop =
            item.node.getClientRects()[0] && item.node.getClientRects()[0].top
          // 设置当前距离可视区小于380的元素为active状态
          if (nodeOffsetTop < 380) {
            this.activeKey = item.key
          }
        }
        // 如果是第一个元素,并且距离可视区顶部已经大于380,则取消其active状态
        if (
          this.nodeList[0].node.getClientRects()[0] &&
          this.nodeList[0].node.getClientRects()[0].top > 380 &&
          this.activeKey === this.nodeList[0].key
        ) {
          this.activeKey = ''
        }
        this.timer = 0
      }, 100)
    },
  },
}
</script>
<style lang="scss" scoped>
.louplus-nav {
  position: fixed;
  top: calc(50% - 235px);
  left: 0;
  margin: 0;
  padding: 5px 0;
  border-bottom-right-radius: 5px;
  border-top-right-radius: 5px;
  list-style: none;
  background-color: #fff;
  box-shadow: 0 10px 15px 0 rgba(0, 0, 0, 0.1);
  font-size: 12px;
  z-index: 9;
  li {
    margin: 3px 0;
    padding: 0 10px 0 7px;
    color: #999;
    cursor: pointer;
    border-left: 3px solid #fff;
    list-style: none;
    &:last-child {
      border: unset !important;
      a {
        display: block;
        padding: 10px 0;
        border-bottom: 1px solid #eee;
        text-align: center;
        border: unset;
        i {
          font-size: 16px;
        }
      }
    }
    &:hover {
      border-left: 3px solid #6ea6ed;
      color: #6ea6ed;
    }
    span {
      display: block;
      padding: 10px 0;
      border-bottom: 1px solid #eee;
      text-align: center;
    }
  }
  li.active {
    border-left: 3px solid #6ea6ed;
    color: #6ea6ed;
  }
}
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值