VitePress用本地文件生成目录
方案选择
VitePress并没有提供像sidebar一样直接的全部文件归档导航块,但是有许多方式可以实现这一功能。
- 手写,最直接方便,鉴于大多数的个人站容量,甚至也是工作量最小的方式,唯一的缺点就是会丧失作为程序员的尊严。
- 动态生成路由,将文档的时间信息挂载在路由上,然后通过VitePress提供的运行时API,useRouter获取全部文件信息并展示。
- 利用VitePress提供的构建时数据加载生成数据并展示。
除此之外VitePress还提供了丰富的构建钩子,选择很多,本次选择上述方案最后一种。
数据加载文件
新建js文件(如docs/.vitepress/theme/md.data.js)
js
import { createContentLoader } from 'vitepress'
export default createContentLoader('/**/*.md', //根目录及根目录下级目录的所有md文件
{
//包含原始markdown源,我的md博文最后都有成文时间;
//也可用fs.statSync读取文件mtime;
includeSrc: true,
transform(rawData) {
return rawData
//加入时间属性,以便排序
.map(e => {
return {
date: e.src.slice(-10),//获取md末尾的成文时间
url: e.url,
}
})
//检查日期是否有效
.filter(e => !Number.isNaN(new Date(e.date).getTime()))
.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime())
},
})
在页面中引用数据
md
<script setup>
import { data } from '../.vitepress/theme/md.data.js'
//data即为md.data.js中transform返回的结果
//业务代码。。。
</script>
md文件中混用markdown与vue语法
VitePress允许在md文件中使用vue语法,但是所有的vue标签也都必须顶格书写,从markdown切换到vue语法还需要额外空行,格式丑陋,而且<h>
标签无法自动生成目录,所以不推荐混用,建议使用组件。
组件
vue
<recordVue />
<script setup>
import recordVue from '../.vitepress/theme/custom/record.vue'
</script>
错误格式
md
<template :class="$style.timeline" v-for="[year,monthly] in annual">
## {{year}}年
<template v-for="[month,records] in monthly">
### {{Number(month)}}月
<template v-for="record in records">
<template v-if="!!record.article">
<p>
<strong>{{Number(record.date.substr(8,2))}}日<a :href="record.article">[{{record.article.slice(record.article.lastIndexOf('/')+1)}}]</a></strong>{{record.record}}
</p>
</template>
<template v-else>
<p><strong>{{Number(record.date.substr(8,2))}}日</strong>{{record.record}}</p>
</template>
</template>
</template>
</template>
正确格式
md
<template :class="$style.timeline" v-for="[year,monthly] in annual">
## {{year}}年
<template v-for="[month,records] in monthly">
### {{Number(month)}}月
<template v-for="record in records">
<template v-if="!!record.article">
<p>
<strong>{{Number(record.date.substr(8,2))}}日<a :href="record.article">[{{record.article.slice(record.article.lastIndexOf('/')+1)}}]</a></strong>{{record.record}}
</p>
</template>
<template v-else>
<p><strong>{{Number(record.date.substr(8,2))}}日</strong>{{record.record}}</p>
</template>
</template>
</template>
</template>
使用css
VitePress不推荐在md中使用<style scoped>
,建议使用<style module>
md
<div :class="$style.timeline">
//...
<div>
<style module>
.timeline {
//...
}
</style>
2025-01-26