惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

宝玉的分享
宝玉的分享
B
Blog RSS Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
MyScale Blog
MyScale Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
SegmentFault 最新的问题
Y
Y Combinator Blog
月光博客
月光博客
IT之家
IT之家
T
Tailwind CSS Blog
Last Week in AI
Last Week in AI
L
LangChain Blog
博客园_首页
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
博客园 - Franky
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
M
MIT News - Artificial intelligence
V
Visual Studio Blog
小众软件
小众软件
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
N
Netflix TechBlog - Medium

Hyde Blog

Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog
Hyde Blog
Hyde · 2025-10-05 · via Hyde Blog

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(() => {
      const { documentElement } = document;
      // 批量读取
      const measurements = {
        offsetHeight: documentElement.offsetHeight,
        scrollTop: documentElement.scrollTop,
      };
      // 批量更新
      if (measurements.scrollTop < 100) {
        top.value = -900;
      } else {
        top.value =
          (900 - (measurements.scrollTop / measurements.offsetHeight) * 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;
  left: 25px;
  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>

vue

<script setup lang="ts" name="TeekLayoutProvider">
// @ts-ignore
import CatBackToTop from "./CatBackToTop.vue"; //导入返回顶部组件
</script>

<template>
  <Teek.Layout>
    <template #layout-top>
      <!--返回顶部组件  -->
      <CatBackToTop />
    </template>
    其他组件...
  </Teek.Layout>
</template>