在使用 VitePress 构建静态网站时,动态路由功能允许我们通过单个 Markdown 文件和动态数据生成多个页面。本文将详细介绍如何使用动态路由以及路径加载器文件来生成这些页面,并提供实例代码和解释说明。
动态路由基础
动态路由的核心在于使用带有参数的路径模板。例如,我们可以创建一个 packages/[pkg].md
文件,为项目中的每个包生成一个对应的页面。这里的 [pkg]
就是一个路由参数,用于区分不同的页面。
路径加载器文件
由于 VitePress 是一个静态站点生成器,因此必须在构建时确定可能的页面路径。因此,每个动态路由页面都必须伴随一个路径加载器文件。对于 packages/[pkg].md
,我们需要一个 packages/[pkg].paths.js
(或 .ts
)文件。
路径加载器文件应导出一个对象,该对象包含一个 paths
方法。paths
方法应返回一个包含 params
属性的对象数组。每个对象都会生成一个对应的页面。
示例代码与解释
单参数动态路由
- 文件结构
.
└─ packages
├─ [pkg].md # 路由模板
└─ [pkg].paths.js # 路由路径加载器
- 路径加载器
// packages/[pkg].paths.js
export default {
paths() {
return [
{ params: { pkg: 'foo' }},
{ params: { pkg: 'bar' }}
]
}
}
- 生成的 HTML 页面
.
└─ packages
├─ foo.html
└─ bar.html
多参数动态路由
- 文件结构
.
└─ packages
├─ [pkg]-[version].md
└─ [pkg]-[version].paths.js
- 路径加载器
// packages/[pkg]-[version].paths.js
export default {
paths: () => [
{ params: { pkg: 'foo', version: '1.0.0' }},
{ params: { pkg: 'foo', version: '2.0.0' }},
{ params: { pkg: 'bar', version: '1.0.0' }},
{ params: { pkg: 'bar', version: '2.0.0' }}
]
}
- 生成的 HTML 页面
.
└─ packages
├─ foo-1.0.0.html
├─ foo-2.0.0.html
├─ bar-1.0.0.html
└─ bar-2.0.0.html
动态生成路径
路径加载器模块在 Node.js 中运行,并且仅在构建时执行。因此,我们可以使用本地或远程数据动态生成路径数组。
- 从本地文件生成路径
// 使用 fs 模块读取本地文件
import fs from 'fs'
export default {
paths() {
return fs
.readdirSync('packages')
.map((pkg) => {
return { params: { pkg }}
})
}
}
- 从远程数据生成路径
// 从远程 API 获取数据
export default {
async paths() {
const pkgs = await (await fetch('https://my-api.com/packages')).json()
return pkgs.map((pkg) => {
return {
params: {
pkg: pkg.name,
version: pkg.version
}
}
})
}
}
在页面中访问参数
动态路由的参数可以通过 $params
全局属性在 Vue 表达式中使用,也可以通过 useData
运行时 API 访问。
- 在 Markdown 文件中访问参数
- package name: {{ $params.pkg }}
- version: {{ $params.version }}
- 在 Vue 组件中访问参数
<script setup>
import { useData } from 'vitepress'
// params 是一个 Vue ref
const { params } = useData()
console.log(params.value)
</script>
渲染原始内容
为了避免在参数中传递大量数据(如原始的 Markdown 或 HTML 内容),可以使用 content
属性。这样,内容将作为 Markdown 文件的一部分直接渲染。
export default {
async paths() {
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
return posts.map((post) => {
return {
params: { id: post.id },
content: post.content // 原始 Markdown 或 HTML
}
})
}
}
在 Markdown 文件中,使用特殊语法 <!-- @content -->
来渲染 content
属性指定的内容。
结论
通过动态路由和路径加载器,VitePress 能够根据动态数据生成多个页面。无论是从本地文件还是远程 API 获取数据,都可以灵活地生成所需的页面路径和参数。希望本文的介绍能够帮助你更好地理解和使用 VitePress 的动态路由功能。