vue3 中实现锚点定位,滚动与导航联动,效果还不错~

20,142 阅读3分钟

src=http___c-ssl.duitang.com_uploads_item_201804_03_20180403232308_KrPJf.thumb.1000_0.jpeg&refer=http___c-ssl.duitang.webp

一个人的时候,怎么过?就算再难以承受,其实到最后我们总能走得过来。

前言

前两天面试的时候,面试官要求附上一个测试作品,给了一个网站(coding.qq.com/home/ ,没错就是这个网站) 让我复刻其中的交互效果,其中就有一块涉及到了锚点定位。因为我之前也没做过这类功能,就觉得挺好玩的,然后也顺手记录一下,要是能帮到某些同学,那就再好不过了~

正文

tip: 这个demo用的是vue3加pinia搭建的,有兴趣的同学,demo源码放在这里哦[~]

第一步 定锚点

给需要定位的组件加上id,后面查找元素需要用到哦(划重点

<template>
  <div class="main-container w" id="main">
    <!-- 通知栏 -->
    <Notice />
    <!-- 赛事活动专区 -->
    <Activity />
    <!-- 编程好工具 -->
    <CodingTool id="labs" />
    <!-- 趣味课程,名师名家带你学 -->
    <Interesting id="courses" />
    <!-- 精彩作品,学以致用 -->
    <Production id="project" />
    <!-- 扣叮动态 -->
    <News id="codingnews" />
    <!-- 校园风采 -->
    <School id="cocase" />
    <!-- 合作伙伴 -->
    <Partner id="cooperator" />
  </div>
</template>

第二步 通过导航栏让锚点动起来!

其实这一步,就是先通过导航栏的点击事件和锚点进行联动,导航栏也就是下面这个东东

image.png

这一步的关键点有以下两个

1. 先使用element.scrollTo方法(使界面滚动到给定元素的指定坐标位置)定义一个锚点定位滚动方法
为了使界面滚动到给定元素(也就是锚点)的指定坐标位置,这里我们用到了这个srollTo这个方法,怎么使用呢,我从mdn截图下来了,可以参考参考,使用方法灰常简单

image.png

image.png

我代码里用的options的参数形式,具体代码如下: 这个方法里需要注意的点:

parent取的是锚点定位元素的可滚动父级元素,这里我拿的是最外层,id为app的元素,大家可以根据实际情况取不同的可滚动父级元素

scrollTo(offsetTop) {
  const parent = document.querySelector('#app')
  parent.scrollTo({
    top: offsetTop,
    behavior: 'smooth'
  })
}

2. 获取锚点的offsetTop(距离父级元素的顶部距离)
上面我们已经定义好了锚点定位的滚动方法,只要向里面传入一个参数(锚点距离父元素的顶部距离offsetTop)就可以愉快地滚动啦。

获取锚点的offsetTop比较简单,使用document.querySelector拿到对应锚点的元素,再取其中offsetTop的属性值就行啦,代码如下:

anchorPosition(anchor) {
  const element = document.querySelector(anchor)
  this.scrollTo(element.offsetTop)
}

这样导航栏跟锚点点击联动的基本工具就搞定了,这一步是不是灰常简单

接下来就是稍稍复杂一丢丢的一步啦~

第三步 锚点滚动时,导航栏也要跟着动哦,来而不往非礼也~

这一步,我的思路是这样子滴:

1. 在页面挂载后(onMounted),先拿到所有锚点的offsetTop,从小到大放到一个数组offsetTopList里方便后面使用;

2. 监听可滚动父元素的scroll事件,编写sroll的处理方法srollHandle;

3. 从大到小反向遍历数组offsetTopList,用滚动时获取的offsetTop值和遍历到的值做对比,只要大于等于遍历到的值,就结束遍历,这也是我发现的比较省事的方法(如果有更好的方法欢迎各位大佬在评论区指点一下,我偷偷学习一下);

4. 结束遍历的时候记得要记录当时的锚点哦,这样导航栏才可以根据这个锚点设置对应的高亮项。;

具体代码如下:

const scrollHandle = ({ target }) => {
  const curScrollTop = target.scrollTop
  let flag = true
  const len = offsetTopList.length
  for (let i = len - 1; i >= 0; i--) {
    const curReference = offsetTopList[i].offsetTop // 当前参考值
    if (flag && curScrollTop >= curReference - 10) {
      flag = false
      sidebarStore.setAnchor(offsetTopList[i].anchor)
    }
  }
}

小结

到这里,其实关于锚点定位的关键步骤就已经完成了,其中待优化的点就是滚动时处理方法得加下节流处理,不然还蛮消耗性能的。没做过又感兴趣的小伙伴也可以试试哦~

本文关键字
1. scrollTo 2. offsetTop

demo源码在此! 溜了溜了