Skip to content

对 vitepress 博客进行个性化修改

发布日期:2023-08-15

本站由vitepress构建,本文将讲述如何对vitepress进行个性化修改,使其更加像一个 blog,而不是 document


首页展示文章列表

我要展示的文章都放在posts/目录里面了,现在需要生成一个首页,自动按文章写作时间倒序展示所有的文章标题和摘要。

比起使用原生的node:fs模块来获取目录中的文章信息,vitepress 为我们提供了方便的工具createContentLoader,可以根据glob规则获取指定目录里面的所有文章。

// index.md 这是首页
<div v-for="item of data" :key="item.url" class="card">
  <div class="header">
    <a :href="item.url">{{ item.frontmatter.title || item.url }}</a>
    <span>{{ dayjs(item.frontmatter.date).format('YYYY-MM-DD') }}</span>
  </div>
  <div class="body" v-html="item.excerpt" v-if="item.excerpt"></div>
</div>

<script lang="ts" setup>
  import { data } from './posts.data.ts'
  import { computed } from 'vue'
  import dayjs from 'dayjs'
</script>

侧边栏展示文章列表

默认主题侧边栏在.vitepress/config.js中的themeConfig.sidebar进行配置,在这里我希望能使用和首页相同的方式获取指定目录中所有的文章。首先createContentLoader是异步获取的,配置文件中需要手动调用load()方法,而配置文件是支持异步的(甚至支持顶层await)。美中不足的是createContentLoader不支持在vitepress 进程外调用,因为内部实现依赖 vitepress 实例,报错如下:

Error: content loader invoked without an active vitepress process, or before vitepress config is resolved.

如果一直开着 vitepress 的开发服务,是不会遇到这个报错的。一旦重启服务,报错就来了。

既然不能在.vitepress/config.js中动态配置,那就只能在 vitepress 实例生成之后进行操作了。我选择了覆盖默认主题的VPSidebar组件,把其中的数据来源替换成由createContentLoader提供。参考覆盖内部组件,首先从官方仓库中下载PSidebar.vue,修改如下的逻辑:

// MyVPSidebar.vue
import { data } from '../../posts.data' // 和首页调用的是同一个 DataLoader,其中使用了 createContentLoader
const { hasSidebar } = useSidebar()
const sidebarGroups = [{
  items: data.map(item => ({
    text: item.frontmatter.title,
    link: item.url
  }))
}]

// .vitepress/config.js
// 这里提供了一个假的页面,因为上面的 hasSidebar 依赖于此处有没有配置项。不去覆写 hasSidebar 的原因是这个参数会被其他组件引用,用于其他组件的样式配合表现,单方面修改会导致其他组件的表现不正常。
sidebar: [
  {
    text: 'fake sidebar',
    link: '/'
  }
]

这个问题我还开了一个 (discussion)[https://github.com/vuejs/vitepress/discussions/2790]

留言板,引入 element-plus 组件库

用户在留言板中提交数据到后台,经过我个人审核后发布,这部分就不详细描述了。

留言板需要用户输入表单,我很喜欢 element-plus 的表单组件,在引入 element-plus 时,我首先想要手动导入,根据官方教程安装unplugin-element-plus用于导入样式,在.vitepress/config.js中配置vite字段的插件。然而一顿操作猛如虎,没有起到该有的作用。于是我就进行了全局导入:

// .vitepress/theme/index.js
import { install } from 'element-plus'
import 'element-plus/dist/index.css'
import DefaultTheme from 'vitepress/theme'
export default {
  ...DefaultTheme,
  enhanceApp(ctx) {
    install(ctx.app)
  },
}

文章标题、日期定制显示样式

我的博客文章结构主要分为3个部分:标题、发布日期、摘要、文章主体。其中标题和发布日期写在 frontmatter 中

---
title: 
data: 
---

摘要(可选)

---

## 二级标题 由于已经有 title 了,所以不写一级标题

正文正文

期望的效果是以上的内容按顺序从上到下排列,但 vitepress 的默认行为并没有附带标题和发布日期,因此这里需要手动修改。vitepress 提供了很多插槽,可以在其中添加需要补充的内容,以下代码利用 doc-before 插槽添加文章标题和发布时间:

// .vitepress/theme/Layout.vue
<template>
  <Layout>
    <template #doc-before>
      <div class="vp-doc" v-if="frontmatter.title">
        <h1>{{ frontmatter.title }}</h1>
        <p style="color: #909399">发布日期:{{ dayjs(frontmatter.date).format('YYYY-MM-DD') }}</p>
      </div>
    </template>
  </Layout>
</template>

<script lang="ts" setup>
import DefaultTheme from 'vitepress/theme'
import { useData } from 'vitepress'
import dayjs from 'dayjs'
const { frontmatter } = useData()
const { Layout } = DefaultTheme
</script>

// .vitepress/theme/index.js
import Layout from './Layout.vue'
export default {
  ...DefaultTheme,
  Layout: Layout
}

半自动化部署

之所以是半自动化部署,主要是因为服务器性能太差了,参考之前的文章。部署方式和那篇文章一致,本地打包后使用ssh2-sftp-client库上传到服务器指定目录,由 nginx 驱动静态页面。

Power by vitepress