Vue实现导航栏绑定内容锚点和滚动内容导航栏变化

<template>
  <div>
      <div v-html="content" class="content"></div>
    <ul class="navs">
      <li
        :class="{ active: active === index }"
        v-for="(item, index) in contenterer"
        @click="scrollTo(item)"
        :key="index"
      >
        {{ item.replace(/#+/g, '') }}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  props: {},
  data() {
    return {
      contenterer: ['#标题1', '#标题2', '#标题3'],
      active: 0, 
      content:
        '<h1 id="标题1">一、标题1</h1>\n<p>内容1</p>\n<p>内容1</p>\n<p>内容1</h1>\n<p>内容1</p>\n<p>内容1</p>\n<p>内容1</p>\n<h1 id="标题2"><br />二、标题2</h1>\n<p>内容2</p>\n<p>内容2</p>\n<p>内容2</p>\n<p>内容2</p>\n<p>内容2</p>\n<p>内容2</p>\n<p>内容2</p>\n<p>内容2</p>\n<h1 id="标题3"><br />三、标题3</h1>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>&nbsp;</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>内容3</p>\n<p>&nbsp;</p>'
    }
  },
  mounted() {
    // 监听滚动事件
    window.addEventListener('scroll', this.onScroll, false)
  },
  destroy() {
    // 必须移除监听器,不然当该vue组件被销毁了,监听器还在就会出错
    window.removeEventListener('scroll', this.onScroll)
  },
  methods: {
    onScroll() {
      const navContents = document.querySelectorAll(
        `.content  ${this.contenterer}`
      )
      const offsetTopArr = []
      navContents.forEach((item) => {
        offsetTopArr.push(item.offsetTop)
      })
      const scrollTop =
        document.documentElement.scrollTop || document.body.scrollTop
      let navIndex = 0
      for (let n = 0; n < offsetTopArr.length; n++) {
        if (scrollTop >= offsetTopArr[n]) {
          navIndex = n
        }
      }
      this.active = navIndex
    },
    scrollTo(index) {
      const targetOffsetTop = document.querySelector(
        `.content ${index}`
      ).offsetTop
      let scrollTop =
        document.documentElement.scrollTop || document.body.scrollTop
      const STEP = 50
      if (scrollTop > targetOffsetTop) {
        smoothUp()
      } else {
        smoothDown()
      }
      function smoothDown() {
        if (scrollTop < targetOffsetTop) {
          if (targetOffsetTop - scrollTop >= STEP) {
            scrollTop += STEP
          } else {
            scrollTop = targetOffsetTop
          }
          document.body.scrollTop = scrollTop
          document.documentElement.scrollTop = scrollTop
          requestAnimationFrame(smoothDown)
        }
      }
      function smoothUp() {
        if (scrollTop > targetOffsetTop) {
          if (scrollTop - targetOffsetTop >= STEP) {
            scrollTop -= STEP
          } else {
            scrollTop = targetOffsetTop
          }
          document.body.scrollTop = scrollTop
          document.documentElement.scrollTop = scrollTop
          requestAnimationFrame(smoothUp)
        }
      }
    }
  }
}
</script>

<style scoped>
.content {
  background-color: white;
  width: 500px;
}
.content div {
  width: 100%;
  height: 600px;
  font-size: 36px;
  padding: 20px;
  background-color: #7ec384;
}
.content div:nth-child(2n) {
  background-color: #847ec3;
}
.navs {
  position: fixed;
  top: 80px;
  left: 700px;
  background-color: #efefef;
}
.navs li {
  padding: 0 20px;
  line-height: 1.6;
  font-size: 24px;
}
.navs .active {
  color: #847ec3;
  background-color: #e2e2e2;
}
</style>

效果:

20230913_141643

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过以下几个步骤实现: 1. 在菜单中添加点击事件,获取对应的锚点id。 2. 使用`ref`属性获取到内容容器的元素。 3. 在内容容器上绑定`scroll`事件,监听滚动位置。 4. 根据当前滚动位置,判断哪个锚点处于可视范围内,并高亮对应的菜单项。 具体代码如下: 菜单部分: ``` <template> <div> <ul> <li v-for="item in menu" :key="item.id" @click="scrollToAnchor(item.id)" :class="{active: activeAnchor === item.id}"> {{ item.title }} </li> </ul> </div> </template> <script> export default { data() { return { menu: [ { id: 'a1', title: '锚点1' }, { id: 'a2', title: '锚点2' }, { id: 'a3', title: '锚点3' } ], activeAnchor: '' // 当前激活的锚点id } }, methods: { scrollToAnchor(anchorId) { // 获取对应的锚点元素 const anchorElement = document.getElementById(anchorId); if (anchorElement) { // 滚动锚点位置 anchorElement.scrollIntoView({ behavior: 'smooth' }); // 设置当前激活的锚点id this.activeAnchor = anchorId; } } } } </script> ``` 内容部分: ``` <template> <div ref="content" @scroll="onScroll"> <div id="a1">锚点1内容</div> <div id="a2">锚点2内容</div> <<div id="a3">锚点3内容</div> </div> </template> <script> export default { methods: { onScroll() { // 获取内容容器的高度和滚动位置 const contentHeight = this.$refs.content.offsetHeight; const scrollTop = this.$refs.content.scrollTop; // 遍历所有锚点,判断哪个处于可视范围内 for (let i = 0; i < this.menu.length; i++) { const anchorId = this.menu[i].id; const anchorElement = document.getElementById(anchorId); if (anchorElement) { const anchorTop = anchorElement.offsetTop; const anchorBottom = anchorTop + anchorElement.offsetHeight; if (scrollTop >= anchorTop && scrollTop < anchorBottom) { // 设置当前激活的锚点id this.$emit('active-anchor', anchorId); break; } } } } } } </script> ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值