返回顶部挂件 原创
新建组件
在docs\.vitepress\theme\components
文件夹下新建BackToTop.vue
文件
提示
vue
// 返回顶部挂件
<template>
<div
class="back_to_top"
ref="toTop"
:style="{
top: top + 'px',
}"
@click="topTop"
></div>
</template>
<script setup lang="ts" name="BackToTop">
import { useRoute } from "vitepress";
import { nextTick, onUnmounted, ref, watch } from "vue";
import { TkMessage } from "vitepress-theme-teek";
import { onMounted } from "vue";
const route = useRoute();
const toTop = ref();
const top = ref<number>(-900);
const offsetHeight = ref<number>(0);
const topTop = () => {
top.value = -900;
window.scrollTo({
top: 0,
behavior: "smooth",
// @ts-ignore Safari兼容
...(typeof CSS !== "undefined" && CSS.supports("scroll-behavior", "smooth")
? {}
: { left: 0 }),
});
TkMessage.success({
message: "已达到顶部🎉",
duration: 3000,
});
};
let animationFrame: number | null = null;
const backToTop = () => {
if (!animationFrame) {
animationFrame = requestAnimationFrame(() => {
offsetHeight.value = document.documentElement.offsetHeight;
const scrollTop = document.documentElement.scrollTop;
if (scrollTop < 100) {
top.value = -900;
} else {
top.value = (900 - (scrollTop / offsetHeight.value) * 900) * -1;
}
animationFrame = null;
});
}
};
onUnmounted(() => {
window.removeEventListener("scroll", backToTop);
});
onMounted(() => {
// 初始化DOM相关操作
offsetHeight.value = document.documentElement.offsetHeight;
// 路由变化时更新高度
watch(
() => route.path,
() => {
nextTick(() => {
offsetHeight.value = document.querySelector("html")!.offsetHeight;
});
},
{ immediate: true }
);
// 添加滚动事件监听
window.addEventListener("scroll", backToTop);
});
</script>
<style lang="scss" scoped>
@keyframes float {
0% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
50% {
-webkit-transform: translateY(-10px);
-ms-transform: translateY(-10px);
transform: translateY(-10px);
}
100% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.back_to_top {
cursor: pointer;
position: fixed;
right: 40px;
top: -900px;
z-index: 1000;
width: 70px;
height: 900px;
background: url("/backToTop/scroll.gif");
transition: all 0.5s ease-in-out;
opacity: 1;
// 新增移动端隐藏
@media (max-width: 768px) {
background: none;
pointer-events: none;
width: 0;
height: 0;
}
&:hover {
animation: float 2s linear infinite;
}
}
</style>
注册组件
在docs\.vitepress\theme\components\TeekLayoutProvider.vue
中注册BackToTop.vue
组件
vue
<script setup lang="ts" name="TeekLayoutProvider">
// @ts-ignore
import BackToTop from "./BackToTop.vue"; //导入返回顶部组件
</script>
<template>
<Teek.Layout>
<template #layout-top>
<!--返回顶部组件 -->
<BackToTop />
</template>
其他组件...
</Teek.Layout>
</template>
效果展示
其他拓展
- 默认移动端不显示,如果需要显示,可注释
BackToTop.vue
中的代码
scss
@media (max-width: 768px) {
background: none;
pointer-events: none;
width: 0;
height: 0;
}
- 控制挂件左右距离
scss
.back_to_top {
right: 40px;
}
- 如果需要返回顶部挂件高度和 body 一致,可以修改
BackToTop.vue
中的代码,列如900
改为100
ts
const backToTop = () => {
if (!animationFrame) {
animationFrame = requestAnimationFrame(() => {
offsetHeight.value = document.documentElement.offsetHeight;
const scrollTop = document.documentElement.scrollTop;
if (scrollTop < 100) {
top.value = -900;
} else {
top.value = (900 - (scrollTop / offsetHeight.value) * 900) * -1;
}
animationFrame = null;
});
}
};