概述
本节深入讲解 Vue Router 的嵌套路由(Nested Routes)在课程学习模块中的应用。重点是如何通过目录结构组织列表页和详情页的路由关系,以及如何在详情页中集成 Markdown 渲染和动态数据加载。
1. 嵌套路由目录结构
1.1 问题场景
学习模块需要两种页面:
- 列表页:
/study-- 展示所有课程列表 - 详情页:
/study/:id-- 展示特定课程的详细信息
使用 vite-plugin-pages 自动路由时,目录结构决定路由层级:
pages/
├── study.vue # 外层基础组件(共享头部 Swiper、Tabs 等)
└── study/
├── index.vue # 列表页 (/study)
└── [id].vue # 详情页外层 (/study/:id)
└── [id]/
└── index.vue # 详情页内容入口
text
1.2 路由层级解析
访问 /study 时:
┌──────────────────────────────────┐
│ default.vue (全局 Layout) │
│ ┌────────────────────────────┐ │
│ │ study.vue (模块基础组件) │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ <RouterView /> │ │ │
│ │ │ → study/index.vue │ │ │ ← 列表页
│ │ └──────────────────────┘ │ │
│ └────────────────────────────┘ │
└──────────────────────────────────┘
访问 /study/1 时:
┌──────────────────────────────────┐
│ default.vue (全局 Layout) │
│ ┌────────────────────────────┐ │
│ │ study.vue (模块基础组件) │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ <RouterView /> │ │ │
│ │ │ → study/[id].vue │ │ │ ← 详情页外层
│ │ │ ┌────────────────┐ │ │ │
│ │ │ │ <RouterView /> │ │ │ │
│ │ │ │ → index.vue │ │ │ │ ← 详情页内容
│ │ │ └────────────────┘ │ │ │
│ │ └──────────────────────┘ │ │
│ └────────────────────────────┘ │
└──────────────────────────────────┘
text
1.3 study.vue -- 模块基础组件
<template>
<div>
<!-- 共享的头部区域:Swiper、分类 Tabs 等 -->
<SwiperSection />
<!-- 子路由渲染出口 -->
<RouterView />
</div>
</template>
vue
study.vue 作为模块的基础组件,提供共享的头部结构,内部通过 <RouterView /> 渲染子路由内容。
2. 动态路由参数
2.1 路径传参
使用方括号 [id] 定义动态路由参数:
pages/study/[id]/index.vue → /study/:id
text
访问 /study/1 时,id 参数值为 1。
2.2 获取路由参数
在详情页中通过 useRoute() 获取动态参数:
<script setup lang="ts">
const route = useRoute()
const courseId = route.params.id
// 根据 ID 加载不同的 Markdown 文件和接口数据
const courseData = await fetchCourseDetail(courseId)
</script>
vue
3. Markdown 组件集成
3.1 导入 Markdown 文件
借助 vite-plugin-vue-markdown,可以将 .md 文件作为 Vue 组件直接导入:
<script setup lang="ts">
import CourseIntro from '../test.md'
</script>
<template>
<CourseIntro />
</template>
vue
3.2 类型声明
为 .md 文件添加 TypeScript 类型声明,避免编译报错:
// env.d.ts
declare module '*.md' {
import { type DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
ts
将此文件放在项目根目录或 src 目录下,TypeScript 即可识别 .md 模块导入。
4. 详情页组件结构
4.1 id.vue -- 详情页外层
<template>
<div class="flex">
<!-- 左侧:课程内容 -->
<div class="w-3/4">
<RouterView />
</div>
<!-- 右侧:推荐课程边栏 -->
<div class="w-1/4">
<!-- 推荐课程列表 -->
</div>
</div>
</template>
vue
4.2 index.vue -- 详情页内容
<script setup lang="ts">
const route = useRoute()
const courseId = route.params.id
</script>
<template>
<div>
<!-- 课程介绍(Markdown 渲染) -->
<CourseIntro />
<!-- 章节目录(接口数据) -->
<Chapters />
<!-- 学员评价(接口数据) -->
<Comments />
</div>
</template>
vue
5. 嵌套路由层级对照表
| 文件路径 | 路由路径 | 职责 |
|---|---|---|
pages/study.vue | /study* | 模块基础组件,共享头部 |
pages/study/index.vue | /study | 列表页入口 |
pages/study/[id].vue | /study/:id | 详情页外层,左右分栏 |
pages/study/[id]/index.vue | /study/:id | 详情页内容,Markdown + 数据 |
6. 核心要点总结
为什么需要两层嵌套? 详情页外层 [id].vue 提供左右分栏的基础布局(左侧内容 + 右侧推荐),内层 index.vue 才是实际的内容渲染入口。这种分离使得:
- 外层可以控制整体布局结构
- 内层专注于 Markdown 渲染和接口数据加载
- 两者各司其职,便于维护
路由参数传递链:route.params.id 在内层 index.vue 中获取,用于决定加载哪个 Markdown 文件以及请求哪条课程数据。
自动路由约定:vite-plugin-pages 根据文件系统结构自动生成路由配置,[param] 语法表示动态参数,index.vue 为目录默认页。
↑