Skip to content

Vitepress 获取所有文章列表

获取目录数据

createContentLoader,当构建一个内容为主的站点时,我们经常需要创建一个“归档”或“索引”页面:一个我们可以列出内容中的所有可用条目的页面,例如博客文章或 API 页面。我们可以直接使用数据加载 API 实现这一点,但由于这会经常使用,VitePress 还提供了一个 createContentLoader 辅助函数来简化这个过程:

js
// .vitepress\common\posts.data.ts
import { createContentLoader } from 'vitepress'

interface Post {
	title: string
	url: string
	excerpt: string | undefined
}

declare const data: Post[]
export { data }

export default createContentLoader('posts/*.md', {
	transform(raw): Post[] {
		return raw.map(({ url, frontmatter }) => ({
			title: frontmatter.title,
			url,
			excerpt: frontmatter.excerpt
		}))
	}
})

在主题目录创建上面文件,读取posts/*.md的文件。

分页组件

PostList.vue组件放在与posts.data.ts相同位置,每10条做分页,以id倒序排列。

vue
<!-- .vitepress\theme\components\layout\PostList.vue -->

<script setup lang="ts">
import { computed, ref } from 'vue'
import { data as posts } from '../../../common/posts.data'
// 当前页数
const currentPage = ref(1)
// 每页文章数
const postsPerPage = 10

// 排序文章,按照倒序排列
const sortedPosts = computed(() => {
	return [...posts].sort((a, b) => {
		const idA = parseInt(a.url.replace('.html', ''))
		const idB = parseInt(b.url.replace('.html', ''))
		return idB - idA // 按照 ID 倒序排列
	})
})

// 计算当前页的文章
const paginatedPosts = computed(() => {
	const start = (currentPage.value - 1) * postsPerPage
	const end = currentPage.value * postsPerPage
	return sortedPosts.value.slice(start, end)
})

// 总页数
const totalPages = computed(() => {
	return Math.ceil(sortedPosts.value.length / postsPerPage)
})

// 切换到下一页
const nextPage = () => {
	if (currentPage.value < totalPages.value) {
		currentPage.value++
	}
}

// 切换到上一页
const prevPage = () => {
	if (currentPage.value > 1) {
		currentPage.value--
	}
}
</script>
<template>
	<h1>学习笔记</h1>
	<div class="xxy">
		<ul>
			<li v-for="{ title, url, excerpt } of paginatedPosts">
				<a :href="url">{{ title }}</a>
				<span>by {{ excerpt }}</span>
			</li>
		</ul>
	</div>
	<!-- 分页控制按钮 -->
	<div class="space-x-4">
		<button @click="prevPage" :disabled="currentPage === 1">上一页</button>
		<span>当前第 {{ currentPage }} 页 共 {{ totalPages }} 页</span>
		<button @click="nextPage" :disabled="currentPage === totalPages">下一页</button>
	</div>
</template>

注册组件:

js

import { h } from 'vue'
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import NotFound from './components/slot/NotFound.vue'

import PostList from './components/layout/PostList.vue'
import 'virtual:uno.css'
import './style.css'
import NoteDoc from './components/layout/NoteDoc.vue'

export default {
	extends: DefaultTheme,
	Layout: () => {
		return h(DefaultTheme.Layout, null, {
			'not-found': () => h(NotFound)
		})
	},
	enhanceApp({ app, router, siteData }) {
		app.component('PostList', PostList)
		app.component('NoteDoc', NoteDoc)
	}
} satisfies Theme

获取文章列表

在文档目录创建 posts/1.md ,posts/2.md 等以数字 id 开头的 md 文档。

创建文章列表:note.md

markdown

#  笔记收藏

<PostList />

文章内容页

我这里沿用的是Vitepress 默认的文档页,新注册一个组件 NoteDoc

vue
<!-- .vitepress\theme\components\layout\NoteDoc.vue -->

<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vitepress'
import { data as posts } from '../../../common/posts.data'
import VPDoc from 'vitepress/dist/client/theme-default/components/VPDoc.vue'

const route = useRoute()

function findCurrentIndex() {
	return posts.findIndex((p) => p.url === route.path)
}

const nextPost = computed(() => posts[findCurrentIndex() - 1])
const prevPost = computed(() => posts[findCurrentIndex() + 1])
</script>

<template>
	<VPDoc>
		<template #doc-top><slot name="doc-top" /></template>
		<template #doc-bottom><slot name="doc-bottom" /></template>

		<template #doc-footer-before><slot name="doc-footer-before" /></template>
		<template #doc-before><slot name="doc-before" /></template>
		<template #doc-after><slot name="doc-after" /></template>

		<template #aside-top><slot name="aside-top" /></template>
		<template #aside-outline-before><slot name="aside-outline-before" /></template>
		<template #aside-outline-after><slot name="aside-outline-after" /></template>
		<template #aside-ads-before><slot name="aside-ads-before" /></template>
		<template #aside-ads-after><slot name="aside-ads-after" /></template>
		<template #aside-bottom><slot name="aside-bottom" /></template>
	</VPDoc>
	<div class="container mx-auto">
		<div class="content flex justify-between">
			<div v-if="nextPost" class="py-8">
				<div class="text-xs tracking-wide uppercase">上一篇</div>
				<div class="link">
					<a :href="nextPost.url">{{ nextPost.title }}</a>
				</div>
			</div>
			<div v-if="prevPost" class="py-8">
				<div class="text-xs tracking-wide uppercase">下一篇</div>
				<div class="link">
					<a :href="prevPost.url">{{ prevPost.title }}</a>
				</div>
			</div>
		</div>
	</div>
</template>

默认展示方式同文档页一样,自己单独加上了上一篇下一篇

markdown
---
layout: NoteDoc
title: Windows环境下安装Nvm配置NodeJS环境
excerpt: 使用NVM搭建NodeJS环境的安装步骤
---

# 笔记标题

  笔记内容

需要展示为笔记的在头部添加 layout: NoteDoc

本站笔记就是这样做的 收藏笔记

🐋