FloatingButtons.vue 1.6 KB
<template>
  <div class="fixed bottom-8 right-8 flex flex-col gap-3 z-50">
    <Transition name="fade">
      <button
        v-show="showBackTop"
        @click="scrollToTop"
        class="w-12 h-12 bg-[#5961f9] hover:bg-[#4751e8] dark:bg-gray-700 dark:hover:bg-gray-600 text-white rounded-full shadow-lg flex items-center justify-center transition-all duration-300 hover:scale-110"
        aria-label="回到顶部"
      >
        <i class="iconfont icon-up_top text-xl"></i>
      </button>
    </Transition>

    <button
      @click="toggleDark"
      class="w-12 h-12 bg-[#5961f9] hover:bg-[#4751e8] dark:bg-gray-700 dark:hover:bg-gray-600 text-white rounded-full shadow-lg flex items-center justify-center transition-all duration-300 hover:scale-110"
      :aria-label="isDark ? '切换到日间模式' : '切换到夜间模式'"
    >
      <i v-if="isDark" class="iconfont icon-sunny text-xl"></i>
      <i v-else class="iconfont icon-moon text-xl"></i>
    </button>
  </div>
</template>

<script lang="ts" setup>
const { isDark, toggleDark } = useDarkMode();

const showBackTop = ref(false);

const handleScroll = () => {
  showBackTop.value = window.scrollY > 300;
};

const scrollToTop = () => {
  window.scrollTo({
    top: 0,
    behavior: "smooth",
  });
};

onMounted(() => {
  window.addEventListener("scroll", handleScroll);
});

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

<style scoped>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>