vitepress趣玩系列——修改源码实现动画标题效果

2,078 阅读5分钟

前言

有一天上Github看代码的时候,发现了一个有趣的网站:Volarjs的官网,可以看到他们首页的title不仅有渐变色,而且有一个动画效果,我们来尝试在我们的vitepress工程中也实现这个效果

通过阅读本文章,你可以学会在使用pnpm的时候,如何通过pnpm patch命令修改源码内容

image.png

基本实现

我们可以通过以下demo来预先实现这个效果

可以看到,实现这个效果其实并不难,只需要文字部分的样式中添加以下代码:

#app {
  background: -webkit-linear-gradient(315deg, rgb(210, 86, 53) 10%, #647eff 50%, rgb(238, 224, 112) 90%);
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;

  background-size: 400% 400%;
  animation: gradient 10s ease infinite;
}

@keyframes gradient {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}

在vitepress中实现

根据我之前的文章:vitepress趣玩系列——首页内容优化,我们可以使用插槽的方式,在文档中插入我们想要展示的组件,所以我们先实现一个带有这种动画效果的组件

在工程中的.vitepress/components下新建组件AnimationTitle.vue

<script setup lang="ts"></script>

<template>
  <div class="title">Vitepress Fun Animation Title</div>
</template>

<style scoped>
.title {
  font-size: 48px;
  line-height: 48px;
  text-align: center;
  margin-top: 20px;

  background: -webkit-linear-gradient(
    315deg,
    rgb(210, 86, 53) 10%,
    #647eff 50%,
    rgb(238, 224, 112) 90%
  );
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;

  background-size: 400% 400%;
  animation: gradient 5s ease infinite;
}

@keyframes gradient {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}
</style>


然后在.vitepress/theme/index.ts中使用插槽,通过查阅源码,找到合适的插槽位置:home-hero-after

import Theme from "vitepress/theme";
import "./style/var.css";
import { h } from "vue";
+ import AnimationTitle from "../components/AnimationTitle.vue";

export default {
  ...Theme,
  Layout() {
    return h(Theme.Layout, null, {
+       "home-features-after": () => h(AnimationTitle),
    });
  },
  enhanceApp({ app }) {},
};

最终效果如下

bd928947-f0e3-4995-a39b-53d434c4f1da.gif

进阶vitepress实现

通过插槽我们可以在文档中的预留位置使用我们的自定义组件,但如果我们希望修改首页图片隔壁的Title样式,也有渐变动画,我们要怎么做呢

首先我们想到的是通过插槽的方式,但通过查阅源码,发现这块并没有预留插槽,只有Hero的上下部分预留了插槽,分别叫home-hero-beforehome-hero-after,使用一下插槽看看效果

import Theme from "vitepress/theme";
import "./style/var.css";
import { h } from "vue";
import AnimationTitle from "../components/AnimationTitle.vue";

export default {
  ...Theme,
  Layout() {
    return h(Theme.Layout, null, {
+      "home-hero-before": () => h(AnimationTitle),
+      "home-hero-after": () => h(AnimationTitle),
      "home-features-after": () => h(AnimationTitle),
    });
  },
  enhanceApp({ app }) {},
};

image.png

  • 方案一,我们不使用首页的Hero,通过插槽home-hero-before来传入我们的自定义Hero,效果如下

image.png

这种方法虽然确实能实现我们想要的效果,但同时我们也要实现图片和按钮组件来完善首页

  • 方案二,修改源码,在title部分添加我们需要的插槽

这方法听着挺硬核,但实现起来其实并不难

一般我们想通过修改依赖来进行打补丁操作,都会首先想到patch-package这个包,但由于我这里使用的是pnpm,在patch-package包的npm文档中能看到,pnpm原生支持这个操作,所以并不需要额外引入工具包

关于pnpm patch的使用方法,官方文档中有详细介绍使用方法,我们先来实操

首先在工程控制台中执行命令

pnpm patch vitepress@1.0.0-alpha.45

这时候会输出如下

image.png

执行这个命令,会创建一个临时工程,我们通过修改这个工程来实现修改依赖的效果,该工程可以通过vscode来打开,在控制台中直接点击生成的路径就能用vscode直接打开临时目录

image.png

可以看到跟vitepress源码并没区别

接下来我们打开临时目录,来修改代码,这里我只贴出关键部分,剩下的会在文章最后说明

image.png

这部分就是标题部分的代码

image.png

在这部分添加一个插槽home-hero-info,这样我们就能通过插槽的方式来修改标题使用自定义组件

代码修改好保存后,我们执行如下命令,用于保存补丁

pnpm patch-commit 临时目录路径

这样在你的工程中就会生成一个目录patches,用来保存修改的内容

image.png

并且package.json也会添加这部分内容

image.png

这样在你每次拉取工程安装依赖的时候,都会执行这部分命令,修改依赖内容

现在我们来试下新增的插槽home-hero-info,修改我们的AnimationTitle.vue组件

<script setup lang="ts"></script>

<template>
  <h1 class="name">
    <span class="clip">VitePress-Fun</span>
  </h1>
  <p class="text">VitePress趣玩系列</p>
  <p class="tagline">Lorem ipsum...</p>
</template>

<style scoped>
.name {
  background: -webkit-linear-gradient(
    315deg,
    rgb(210, 86, 53) 10%,
    #647eff 50%,
    rgb(238, 224, 112) 90%
  );
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;

  background-size: 400% 400%;
  animation: gradient 5s ease infinite;
}

@keyframes gradient {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}

.name,
.text {
  max-width: 392px;
  letter-spacing: -0.4px;
  line-height: 40px;
  font-size: 32px;
  font-weight: 700;
  white-space: pre-wrap;
}
@media (min-width: 640px) {
  .name,
  .text {
    max-width: 576px;
    line-height: 56px;
    font-size: 48px;
  }
}
@media (min-width: 960px) {
  .name,
  .text {
    line-height: 64px;
    font-size: 56px;
  }
}

.tagline {
  padding-top: 8px;
  max-width: 392px;
  line-height: 28px;
  font-size: 18px;
  font-weight: 500;
  white-space: pre-wrap;
  color: var(--vp-c-text-2);
}
@media (min-width: 640px) {
  .tagline {
    padding-top: 12px;
    max-width: 576px;
    line-height: 32px;
    font-size: 20px;
  }
}

@media (min-width: 960px) {
  .tagline {
    line-height: 36px;
    font-size: 24px;
  }
}
</style>

然后使用插槽

import Theme from "vitepress/theme";
import "./style/var.css";
import { h } from "vue";
import AnimationTitle from "../components/AnimationTitle.vue";

export default {
  ...Theme,
  Layout() {
    return h(Theme.Layout, null, {
+      "home-hero-info": () => h(AnimationTitle),
    });
  },
  enhanceApp({ app }) {},
};

现在我们来看下效果

ce233c83-db71-4b71-9e27-b27ddfc22a58.gif

现在我们就能实现标题部分有渐变动画的效果了

后记

其实这篇文章在一个月前就想写了,因为看到Volarjs的官网后灵感浮现,也想自己实现一个类似的效果,但无奈vitepress官方并不支持修改标题,也就是不在这个位置预留插槽位,我本来也是跟Volarjs文档一样,想自己重写一个Home组件,无奈实在是太懒了,于是我就给官方提了个PR,希望他们能正式支持这个插槽,点击这里可以看到我3周前提的PR

但等了好久,官方始终不合这个PR,可能官方并不希望这个位置能被修改吧

完整的插槽修改方式代码可以查看我提的PR里的修改内容,其实添加一个插槽并不难,各位可以通过这个方法,来实现自己想要的效果