简单介绍
在 vitepress 中,文档的切换非常迅速,以至于我们如果注意力不集中很容易没有发现文档切换了,聪明的我们还以为点击链接没有效果或者卡住了
为了解决这个问题,我们需要在路由切换时增加一些贼拉漂亮的动画效果,让文档切换更流畅,更自然
来看看官方文档怎么让路由切换有动画效果吧:
现在它真的要到来了!
其实要实现这个效果很简单,不知道官网为啥鸽了
我是基于官网介绍的 布局插槽 实现的
实现的关键点:
- 使用布局插槽来让显示文档的区域插入一个遮罩层
- 给这个遮罩层添加一个可以由 JS 控制的动画效果
- 监听路由切换,在路由切换时,控制遮罩层的动画效果
效果展示
先展示最终代码,之后再详细讲解
如果你不想看详细解释并对自己的实力有信心,可以不用看下面的详细解释,直接从代码中获取关键信息并在自己的项目中实现路由切换动画。很简单的
.vitepress/theme/MyLayout.vue
<script setup>
import { useRouter } from "vitepress";
import DefaultTheme from "vitepress/theme";
import { watch, ref } from "vue";
const { Layout } = DefaultTheme;
const { route } = useRouter();
const isTransitioning = ref(false);
watch(
() => route.path,
() => {
isTransitioning.value = true;
// 动画结束后重置状态
setTimeout(() => {
isTransitioning.value = false;
}, 500); // 500ms 要和 CSS 动画时间匹配
}
);
</script>
<template>
<Layout>
<template #doc-top>
<div class="shade" :class="{ 'shade-active': isTransitioning }">
</div>
</template>
</Layout>
</template>
<style>
.shade {
position: fixed;
width: 100%;
height: 100vh;
background-color: rgb(255, 255, 255);
z-index: 100;
pointer-events: none;
opacity: 0;
transition: transform 0.5s ease-in-out;
}
.shade-active {
opacity: 0;
animation: shadeAnimation 0.5s ease-in-out;
}
@keyframes shadeAnimation {
0% {
opacity: 1;
transform: translateY(0);
}
50% {
opacity: 1;
}
100% {
opacity: 0;
transform: translateY(100vh);
}
}
</style>
.vitepress/theme/index.ts
import DefaultTheme from "vitepress/theme";
import { Theme } from "vitepress";
import MyLayout from "./MyLayout.vue";
const theme: Theme = {
extends: DefaultTheme,
Layout: MyLayout,
};
export default theme;
给显示文档的区域插入一个遮罩层
主题入口文件
首先要明白如何扩展默认主题
vitepress 中可以通过创建一个 .vitepress/theme/index.js 或 .vitepress/theme/index.ts 文件 (即“主题入口文件”) 来启用自定义主题
在主题入口文件中,可以直接创建一个新的主题来覆盖掉默认主题,但是最好别这样做(vitepress 的默认主题还是很靠谱的)
如果你确实觉得默认主题就是一坨答辩,可以去看看官方文档中的 配置和 API 参考
更多时候,我们希望扩展默认主题,比如添加一个布局插槽,或者修改默认主题的样式
上面的 .vitepress/theme/index.ts 文件是一个没有任何多余东西的扩展主题,它使用注入插槽的包装组件(MyLayout)覆盖原始的 Layout。如果你的项目中没有其它东西修改过 index.ts(vitepress 的新手),那么可以直接复制
MyLayout.vue 布局文件
现在关键来到了 .vitepress/theme/MyLayout.vue 文件
它其实就是一个 Vue 单文件组件,不同的是如果你想要扩展默认主题,那么应该提供 vitepress 暴露的 Layout 组件
<template>
<Layout>
<template #doc-top>
<div class="shade">
</div>
</template>
</Layout>
</template>
其中的 #doc-top 是一个插槽的位置,关于插槽的更多内容请查看官方文档 布局插槽
丰富遮罩层的样式并添加可以由 JS 控制的动画效果
如果你熟悉 js、css 和 vue,那么这一步你会很熟悉
<script setup>
import DefaultTheme from "vitepress/theme";
import { ref } from "vue";
const { Layout } = DefaultTheme;
const isTransitioning = ref(false);
</script>
<template>
<Layout>
<template #doc-top>
<div class="shade" :class="{ 'shade-active': isTransitioning }">
</div>
</template>
</Layout>
</template>
<style>
.shade {
position: fixed;
width: 100%;
height: 100vh;
background-color: rgb(255, 255, 255);
z-index: 100;
pointer-events: none;
opacity: 0;
transition: transform 0.5s ease-in-out;
}
.shade-active {
opacity: 0;
animation: shadeAnimation 0.5s ease-in-out;
}
@keyframes shadeAnimation {
0% {
opacity: 1;
transform: translateY(0);
}
50% {
opacity: 1;
}
100% {
opacity: 0;
transform: translateY(100vh);
}
}
</style>
代码看起来增加了很多,其实主要是 CSS 动画,如果你非常熟悉 CSS,那么可以自定义你的动画效果。你甚至可以使用 gsap 等动画库(需要安装依赖)。如果你是新手,直接复制吧,还说啥呢
别忘了关键的 isTransitioning 响应式变量,它将是下一步的关键
监听路由切换,控制动画效果
距离完成还有最后一步,如果你熟悉 VueRouter, 那么这一步你会很熟悉
实际上 VitePress 是基于 VueRouter 实现路由跳转的,但是它对 VueRouter 做了封装
要控制路由与原版 VueRouter 一样,关键是获取路由实例的方法变成了 vitepress 提供的 useRouter() 函数
现在在 MyLayout.vue 中获取到路由实例,监听路由的变化,然后在路由变化时控制遮罩层的动画效果
<script setup>
import { useRouter } from "vitepress";
import { watch, ref } from "vue";
const { Layout } = DefaultTheme;
const { route } = useRouter();
const isTransitioning = ref(false);
watch(
() => route.path,
() => {
isTransitioning.value = true;
// 动画结束后重置状态
setTimeout(() => {
isTransitioning.value = false;
}, 500); // 500ms 要和 CSS 动画时间匹配
}
);
</script>
注意:如果不监听路由变化,那么动画效果将只会生效一次,具体原因是因为 Layout 组件只会被渲染一次
完成
如果大佬们有更好的方法,可以在评论区留言
萌新们别忘了看看评论区,大佬们总是会在评论区出现