VitePress 系列教程:自动生成侧边栏 #7
在做博客的时候,制作博客首页的时候的需要获取文章详情数据构建目录页,有时候还需要对文章进行分类、排序等其他操作。这一节我们来学习如果获取文章的元数据,构建自己想要实现的页面。
自动侧边栏
使用 VitePress 构建博客的时候,侧边栏需要自己手动配置。当文章与目录一多,就特别麻烦。但是可以自己使用 node.js 编写代码,实现自动生成侧边栏。
1、先定义需要过滤的白名单,把 index.md
与 .vitepress
等之类的文件或者目录给过滤掉。
js
// 文件根目录
const DIR_PATH = path.resolve()
// 白名单,过滤不是文章的文件和文件夹
const WHITE_LIST = ['index.md', '.vitepress', 'node_modules', '.idea', 'assets']
2、遍历目录下的文件与文件夹,并且过滤白名单
js
import path from 'node:path'
import fs from 'node:fs'
// 文件根目录
const DIR_PATH = path.resolve()
// 白名单,过滤不是文章的文件和文件夹
const WHITE_LIST = ['index.md', '.vitepress', 'node_modules', '.idea', 'assets']
// 判断是否是文件夹
const isDirectory = (path) => fs.lstatSync(path).isDirectory()
// 取差值
const intersections = (arr1, arr2) => Array.from(new Set(arr1.filter((item) => !new Set(arr2).has(item))))
export const set_sidebar = (pathname) => {
// 获取 pathname 的路径
const dirPath = path.join(DIR_PATH, pathname)
// 读取 pathname 下的所有文件或者文件夹
const files = fs.readdirSync(dirPath)
// 过滤掉
const items = intersections(files, WHITE_LIST)
console.log(items)
return {}
}
3、递归遍历目录,生成侧边栏菜单
js
// 把方法导出直接使用
function getList(params, path1, pathname) {
// 存放结果
const res = []
// 开始遍历params
for (let file in params) {
// 拼接目录
const dir = path.join(path1, params[file])
// 判断是否是文件夹
const isDir = isDirectory(dir)
if (isDir) {
// 如果是文件夹,读取之后作为下一次递归参数
const files = fs.readdirSync(dir)
res.push({
text: params[file],
collapsible: true,
items: getList(files, dir, `${pathname}/${params[file]}`),
})
} else {
// 获取名字
const name = path.basename(params[file])
// 排除非 md 文件
const suffix = path.extname(params[file])
if (suffix !== '.md') {
continue
}
res.push({
text: name,
link: `${pathname}/${name}`,
})
}
}
return res
}
使用
js
import {defineConfig} from 'vitepress'
import {set_sidebar} from './set_sidebar.mjs'
export default defineConfig({
themeConfig: {
sidebar: {'/nuxt3': set_sidebar('nuxt3')},
},
})
完整代码
js
import path from 'node:path'
import fs from 'node:fs'
// 文件根目录
const DIR_PATH = path.resolve()
// 白名单,过滤不是文章的文件和文件夹
const WHITE_LIST = ['index.md', '.vitepress', 'node_modules', '.idea', 'assets']
// 判断是否是文件夹
const isDirectory = (path) => fs.lstatSync(path).isDirectory()
// 取差值
const intersections = (arr1, arr2) => Array.from(new Set(arr1.filter((item) => !new Set(arr2).has(item))))
// 把方法导出直接使用
function getList(params, path1, pathname) {
// 存放结果
const res = []
// 开始遍历params
for (let file in params) {
// 拼接目录
const dir = path.join(path1, params[file])
// 判断是否是文件夹
const isDir = isDirectory(dir)
if (isDir) {
// 如果是文件夹,读取之后作为下一次递归参数
const files = fs.readdirSync(dir)
res.push({
text: params[file],
collapsible: true,
items: getList(files, dir, `${pathname}/${params[file]}`),
})
} else {
// 获取名字
const name = path.basename(params[file])
// 排除非 md 文件
const suffix = path.extname(params[file])
if (suffix !== '.md') {
continue
}
res.push({
text: name,
link: `${pathname}/${name}`,
})
}
}
return res
}
export const set_sidebar = (pathname) => {
// 获取pathname的路径
const dirPath = path.join(DIR_PATH, pathname)
// 读取pathname下的所有文件或者文件夹
const files = fs.readdirSync(dirPath)
// 过滤掉
const items = intersections(files, WHITE_LIST)
// getList 函数后面会讲到
return getList(items, dirPath, pathname)
}
获取文章元数据
在做文章目录页的时候,需要获取一些文章里面的数据,这时候就可以使用 VitePress 默认提供的 createContentLoader
方法。
js
// posts.data.js
import {createContentLoader} from 'vitepress';
const pages = createContentLoader('/posts/*.md', {
includeSrc: false,
render: false,
excerpt: false,
transform(rawData) {
return rawData.sort((a, b) => {
return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date);
});
},
});
export default pages;
部署
运行 npm run docs:build
就可以将内容打包为静态内容,这个项目可以在 gitee pages 、github pages 进行托管,也可以自己购买服务器使用 nginx 之类的工具进行部署,甚至可以用 oss、cos 之类的工具进行部署。
最好是提前准备一个域名。