vue3自定义动态锚点列表,实现本页面锚点跳转效果

Vue3实现本页面动态锚点跳转效果

需求:当前页面存在多个模块且内容很长时,需要提供一个锚点列表,可以快速查看对应模块内容

实现步骤:

1.每个模块添加唯一id,添加锚点列表div

<template>
  <!-- 模块A -->
  <div id="modalA">
    <ModalA/>
  </div>
  <!-- 模块B -->
  <div id="modalB">
    <ModalB/>
  </div>
  
  <!-- 动态锚点 -->
    <div class="anchor-box">
      <ul>
        <li v-for="(item, index) in status.anchors" :key="index" :class="{'active': status.anchorActive===index}" @click="onAnchor(item, index)">
          <i class="spot"></i>
          <span>{{ item.title }}</span>
        </li>
      </ul>
    </div>
</template>

2.初始化锚点列表,监听滚动事件

<script lang='ts' setup>
import { debounce } from "lodash-es";

const status:any = reactive({
  anchors: [], // 动态锚点集合
  anchorActive: -1, // 锚点高亮
});

onMounted(() => {
  init()
});

const init = () => {
  initAnchors()
  // 这里的content-wrap是设置overflow-y:auto的div,如果滚动条是全局的可以改成window,即:window.addEventListener('scroll',  handleScroll)
  scrollDom.value = document.querySelector('.content-wrap')
  scrollDom.value.addEventListener('scroll',  handleScroll)
}

// 设置动态锚点集合
const initAnchors = () => {
  status.anchors = [
    {
      title: "模块A",
      id: "modalA"
    },
    {
      title: "模块B",
      id: "modalB"
    },
  ]
}

// 监听滚动
const handleScroll = () => {
  let scrollPosition = scrollDom.value.scrollTop
  status.anchors.forEach((v, index) => {
    let dom = document.getElementById(`${v.id}`)
    const offsetTop = dom.offsetTop  
    const offsetHeight = dom.offsetHeight
    if (scrollPosition >= offsetTop && scrollPosition < offsetTop + offsetHeight) {
      status.anchorActive = index
    }
  })
}

// 锚点跳转
const onAnchor = (item, index) => {
  // 移除scroll事件
  scrollDom.value.removeEventListener('scroll', handleScroll)
  status.anchorActive = index

  nextTick(() => {
    const target = document.getElementById(item.id);
    target?.scrollIntoView({
      behavior: 'smooth',
      block: 'start',     // 垂直对齐方式(start/center/end)
      inline: 'nearest'   // 水平对齐方式
    });

    // 重新绑定scroll事件
    addScrollEvent()
  })
}

// 绑定scroll事件
const addScrollEvent = debounce(() => {
  scrollDom.value.addEventListener('scroll', handleScroll)
}, 1500)
</script>

3.设置锚点样式


  .anchor-box {
    position: fixed;
    top: 100px;
    right: 50px;
    width: 120px;
    height: calc(100vh - 80px - 40px);
    overflow-y: auto;
    &::-webkit-scrollbar {
      width: 0;
    }
    ul {
      position: relative;
      list-style: none;
      padding: 4px;
      box-sizing: border-box;
      background-color: rgba(240, 242, 245, 0.8);
      &:before {
        position: absolute;
        top: 0;
        left: 7px;
        width: 2px;
        height: 100%;
        background-color: #dbdada;
        content: " ";
      }
      li {
        position: relative;
        width: 100%;
        display: flex;
        margin-bottom: 6px;
        cursor: pointer;
        &.active {
          .spot {
            display: block;
          }
          > span {
            color: #1890ff;
          }
        }
        .spot {
          display: none;
          position: absolute;
          top: 6px;
          width: 8px;
          height: 8px;
          background-color: #fff;
          border: 2px solid #1890ff;
          border-radius: 50%;
          transition: top .3sease-in-out;
        }
        > span {
          width: 100%;
          line-height: 1.5;
          padding-left: 16px;
          box-sizing: border-box;
          font-size: 13px;
        }
      }
    }
  }

最终效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清岚_lxn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值