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

推荐订阅源

雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
大猫的无限游戏
大猫的无限游戏
Google DeepMind News
Google DeepMind News
V
V2EX
T
The Blog of Author Tim Ferriss
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Hugging Face - Blog
Hugging Face - Blog
Stack Overflow Blog
Stack Overflow Blog
I
InfoQ
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Last Week in AI
Last Week in AI
Recent Announcements
Recent Announcements
Vercel News
Vercel News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tailwind CSS Blog
美团技术团队
Martin Fowler
Martin Fowler
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
J
Java Code Geeks

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>