在vue3中封装一个滚动进度条

1,764 阅读1分钟

前言

使用的框架是vue3,但是核心逻辑是js原生写的,所以可以很方便移植到其他框架。

实现

先看效果: QQ录屏20230510171619 -original-original.gif

来实现吧:

首先,进度条的宽度等于页面总的可滚动高度除以已经滚动高度,所以我们只要计算出这两个量计算再赋值给滚动条的宽度就可以了。

      // 获取页面的总高度
      const pageHeight =
        document.body.scrollHeight || document.documentElement.scrollHeight;

      // 获取可见高度
      const canSeeHeight = document.body.clientHeight;

      // 可以滚动的高度
      const canScrollHeight = pageHeight - canSeeHeight;
      // 已经滚动的高度
      const scrollTop =
        document.documentElement.scrollTop || document.body.scrollTop;
      // 滚动条宽度计算
      const width = (scrollTop / canScrollHeight) * 100 + "%";
      // 给定宽度
      wordScroll.value!.style.width = width;

这样效果就实现了,但是性能上还差点,现在来优化性能:

function updateWidth() {
  clearTimeout(window.timer);
  window.timer = setTimeout(() => {
    window.requestAnimationFrame(() => {
      // 获取页面的总高度
      const pageHeight =
        document.body.scrollHeight || document.documentElement.scrollHeight;

      // 获取可见高度
      const canSeeHeight = document.body.clientHeight;

      // 可以滚动的高度
      const canScrollHeight = pageHeight - canSeeHeight;
      // 已经滚动的高度
      const scrollTop =
        document.documentElement.scrollTop || document.body.scrollTop;
      // 滚动条宽度计算
      const width = (scrollTop / canScrollHeight) * 100 + "%";
      // 给定宽度
      wordScroll.value!.style.width = width;
    });
  }, 20);
}

这里我使用的是防抖函数,没有使用节流函数的原因是因为节流会导致最后一段宽度加不上,所以使用防抖比较好。 还有就是这里使用到了window.requestAnimationFrame这个方法传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。这样有助于性能优化。 最后别忘了最后要在onBeforeUnmount中移除回调

完整代码

<template>
  <!-- 进度条 -->
  <div
    ref="wordScroll"
    class="word-scroll z-50 fixed top-0 left-0 h-1 bg-blue-400 transition-all duration-100"
  />
</template>

<script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref } from "vue";
const wordScroll = ref<HTMLElement>();

/**
 * 页面滚动
 */

function updateWidth() {
  // @ts-ignore
  clearTimeout(window.timer);
  // @ts-ignore
  window.timer = setTimeout(() => {
    window.requestAnimationFrame(() => {
      // 获取页面的总高度
      const pageHeight =
        document.body.scrollHeight || document.documentElement.scrollHeight;

      // 获取可见高度
      const canSeeHeight = document.body.clientHeight;

      // 可以滚动的高度
      const canScrollHeight = pageHeight - canSeeHeight;
      // 已经滚动的高度
      const scrollTop =
        document.documentElement.scrollTop || document.body.scrollTop;
      // 滚动条宽度计算
      const width = (scrollTop / canScrollHeight) * 100 + "%";
      // 给定宽度
      wordScroll.value!.style.width = width;
    });
  }, 20);
}
onMounted(() => {
  window.addEventListener("scroll", updateWidth);
});

onBeforeUnmount(() => {
  window.removeEventListener("scroll", updateWidth);
});
</script>