本站由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 驱动静态页面。