VitePress 与 Vue Router
深入理解 VitePress 的路由机制,掌握文件路由、动态路由和编程式导航。
路由架构
VitePress 路由 vs Vue Router
VitePress 基于文件系统自动生成路由,底层使用的是简化版的 Vue Router:
| 特性 | VitePress 路由 | 标准 Vue Router |
|---|---|---|
| 路由定义 | 基于文件系统自动生成 | 手动配置 |
| 动态路由 | 通过 paths 文件 | 通过 :param 语法 |
| 嵌套路由 | 目录层级自动映射 | 手动配置 children |
| 路由守卫 | onBeforeRouteChange | beforeEach 等 |
| 懒加载 | 自动按页面分割 | 手动 import() |
文件到路由的映射规则
docs/
├── index.md → /
├── about.md → /about
├── guide/
│ ├── index.md → /guide/
│ ├── installation.md → /guide/installation
│ └── advanced/
│ └── ssr.md → /guide/advanced/ssr
└── api/
├── index.md → /api/
└── [id].md → /api/:id(动态路由)useRoute 和 useRouter
useRoute — 获取当前路由信息
vue
<script setup lang="ts">
import { useRoute } from 'vitepress'
const route = useRoute()
</script>
<template>
<div>
<p>当前路径: {{ route.path }}</p>
<p>页面数据: {{ route.data.title }}</p>
<p>Frontmatter: {{ route.data.frontmatter }}</p>
</div>
</template>useRouter — 编程式导航
vue
<script setup lang="ts">
import { useRouter } from 'vitepress'
const router = useRouter()
function navigateToGuide() {
// 导航到指定路径
router.go('/guide/')
}
function goBack() {
// 后退一步
router.go(-1)
}
function goForward() {
// 前进一步
router.go(1)
}
</script>路由钩子
可用的路由钩子
typescript
// .vitepress/theme/index.ts
import { useRouter } from 'vitepress'
export default {
setup() {
const router = useRouter()
// 页面跳转前
router.onBeforeRouteChange = (to) => {
console.log('即将导航到:', to)
// 返回 false 可取消导航
}
// 页面加载前
router.onBeforePageLoad = (to) => {
console.log('开始加载页面:', to)
}
// 页面加载后
router.onAfterPageLoad = (to) => {
console.log('页面加载完成:', to)
}
// 路由切换后(DOM 已更新)
router.onAfterRouteChanged = (to) => {
console.log('路由已切换到:', to)
// 可用于页面分析、滚动重置等
}
}
}实际应用场景
页面访问统计
typescript
router.onAfterRouteChanged = (to) => {
// 上报页面访问
if (typeof window !== 'undefined' && window.gtag) {
window.gtag('config', 'GA-ID', {
page_path: to
})
}
}页面切换进度条
typescript
import { ref } from 'vue'
const isLoading = ref(false)
router.onBeforeRouteChange = () => {
isLoading.value = true
}
router.onAfterRouteChanged = () => {
isLoading.value = false
}路由切换时滚动到顶部
typescript
router.onAfterRouteChanged = () => {
window.scrollTo(0, 0)
}动态路由
创建动态路由页面
使用 [param].md 语法创建动态路由:
docs/
├── blog/
│ ├── [id].md # /blog/:id
│ └── [id].paths.ts # 动态路由数据定义路径数据
typescript
// docs/blog/[id].paths.ts
import { createContentLoader } from 'vitepress'
export default {
async paths() {
const posts = await createContentLoader('blog/*.md')
return posts.map(post => ({
params: {
id: post.url.replace('/blog/', '').replace('.html', '')
},
content: post.excerpt
}))
}
}在页面中使用参数
markdown
---
title: 博客文章
---
<!-- docs/blog/[id].md -->
<script setup lang="ts">
import { useData } from 'vitepress'
const { page } = useData()
const postId = page.value.params.id
</script>
<template>
<article>
<h1>文章 ID: {{ postId }}</h1>
</article>
</template>路由重写
配置路由重写
typescript
// .vitepress/config.mts
export default defineConfig({
rewrites: {
// 将 zh/guide/ 重写为 guide/
'zh/guide/:id': 'guide/:id',
'en/guide/:id': 'en/guide/:id'
}
})重写与 i18n
路由重写常用于国际化场景,将不同语言的源文件映射到不同的路由:
源文件结构:
docs/
├── zh/
│ └── guide/
│ └── index.md
├── en/
│ └── guide/
│ └── index.md
重写后的路由:
/zh/guide/ → /guide/ (中文)
/en/guide/ → /en/guide/ (英文)404 路由
自定义 404 页面
创建 docs/404.md:
markdown
---
layout: page
---
<div class="not-found">
<h1>404</h1>
<p>页面未找到</p>
<a href="/">返回首页</a>
</div>
<style scoped>
.not-found {
text-align: center;
padding: 96px 24px;
}
</style>在主题中自定义 404
typescript
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import NotFound from './NotFound.vue'
export default {
extends: DefaultTheme,
NotFound // 自定义 404 组件
}SPA 路由 vs MPA 路由
SPA 路由(默认)
- 页面切换由 Vue Router 处理
- 不刷新浏览器
- 支持 Vue 过渡动画
- JS bundle 较大
MPA 路由
typescript
export default defineConfig({
mpa: true
})- 每次导航都是完整的页面请求
- 无 JavaScript 依赖
- 更快的首屏加载
- 不支持客户端路由钩子
常见问题
路由不生效
检查文件路径是否正确,注意:
- 文件名使用小写字母和连字符
index.md对应目录根路径- 不需要
.md或.html后缀
动态路由页面为空
确保 [param].paths.ts 文件正确导出了 paths 函数,且返回的 params 与文件名中的参数名匹配。
路由钩子在 MPA 模式下不生效
MPA 模式没有客户端路由,路由钩子不可用。使用 SPA 模式或改用服务端方案。
相关链接
- 路由详解 — 基础路由配置
- 路由重写 — 路由重写配置
- 运行时 API — useRoute 和 useRouter
- VitePress 原理与架构 — 底层架构解析