Skip to content

路由切换遮罩

新建组件

docs\.vitepress\theme\components目录下新建RouteSwitchingLoading.vue组件

vue
<!-- 路由切换动画组件 -->
<script setup lang="ts">
import { ref, watch, onMounted } from "vue";
import { useRoute } from "vitepress";

const route = useRoute();
const transitionKey = ref(route.path);
const loading = ref(false);

// 动画时长可配置,便于调试
const ANIMATION_DURATION = 350;

// 路由切换时处理 loading
function handleRouteChange(newPath: string, oldPath: string) {
  if (newPath === oldPath) return;
  loading.value = true;
  setTimeout(() => {
    transitionKey.value = newPath;
    loading.value = false;
  }, ANIMATION_DURATION);
}

// 监听路由变化
onMounted(() => {
  watch(() => route.path, handleRouteChange, { immediate: false });
});
</script>

<template>
  <Transition name="fade-route" mode="out-in">
    <div :key="transitionKey">
      <slot />
    </div>
  </Transition>
  <transition name="fade-mask">
    <div v-if="loading" class="route-mask">
      <slot name="loader">
        <div class="loader"></div>
        <span class="loading-text">loading...</span>
      </slot>
    </div>
  </transition>
</template>

<style scoped>
.fade-route-enter-active,
.fade-route-leave-active {
  transition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.fade-route-enter-from,
.fade-route-leave-to {
  opacity: 0;
}

.fade-route-enter-to,
.fade-route-leave-from {
  opacity: 1;
}

.fade-mask-enter-active,
.fade-mask-leave-active {
  transition: opacity 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

.fade-mask-enter-from,
.fade-mask-leave-to {
  opacity: 0;
}

.fade-mask-enter-to,
.fade-mask-leave-from {
  opacity: 1;
}

.route-mask {
  position: fixed;
  z-index: 99999;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(255, 255, 255, 0.7);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: all;
}

/* 简单 loading 动画 */
.loader {
  border: 4px solid #f3f3f3;
  border-top: 4px solid var(--vp-c-brand-1);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  animation: spin 1s linear infinite;
  margin-bottom: 16px;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.loading-text {
  color: var(--vp-c-brand-1);
  font-size: 1.1rem;
  font-weight: 500;
  letter-spacing: 2px;
}
</style>

注册组件

docs\.vitepress\theme\components\TeekLayoutProvider.vue中注册组件

vue
<script setup lang="ts" name="TeekLayoutProvider">
// @ts-ignore 路由切换遮罩过渡动画
import RouteSwitchingLoading from "./RouteSwitchingLoading.vue"; 
</script>

<template>
  <Teek.Layout>
    <template #layout-top>
      <!-- 路由切换动画组件 -->
      <RouteSwitchingLoading/>
      <!-- 其他组件 -->
    </template>
  </Teek.Layout>
</template>
最近更新