前言
使用的框架是vue3,但是核心逻辑是js原生写的,所以可以很方便移植到其他框架。
实现
先看效果:
来实现吧:
首先,进度条的宽度等于页面总的可滚动高度除以已经滚动高度,所以我们只要计算出这两个量计算再赋值给滚动条的宽度就可以了。
// 获取页面的总高度
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>