62. 路由配置与嵌套路由
📖 概述
嵌套路由是Vue Router的核心功能之一,允许我们在一个路由组件内部嵌套另一个路由组件,从而实现更复杂的页面结构。本集将深入讲解Vue Router 4.x的路由配置进阶技巧,包括嵌套路由的定义、配置、使用场景以及最佳实践,帮助你构建具有多层次结构的单页应用。
✨ 核心知识点
1. 嵌套路由基础
什么是嵌套路由
- 嵌套路由允许在一个路由组件内部渲染另一个路由组件
- 形成父子路由关系,反映页面的层次结构
- 适用于具有复杂布局的应用,如后台管理系统
嵌套路由的使用场景
- 后台管理系统:主布局包含侧边栏和主内容区,主内容区根据路由动态变化
- 电商网站:产品详情页包含多个标签页(介绍、评论、规格等)
- 社交媒体应用:用户主页包含动态、相册、好友列表等
2. 配置嵌套路由
基本配置
// src/router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'home',
component: () => import('../views/HomeView.vue')
},
{
path: '/dashboard',
name: 'dashboard',
component: () => import('../views/DashboardView.vue'),
// 嵌套路由配置
children: [
{
// 子路由路径,相对于父路由
path: '', // 空路径表示默认子路由
name: 'dashboard-home',
component: () => import('../views/DashboardHomeView.vue')
},
{
path: 'profile',
name: 'dashboard-profile',
component: () => import('../views/DashboardProfileView.vue')
},
{
path: 'settings',
name: 'dashboard-settings',
component: () => import('../views/DashboardSettingsView.vue')
}
]
}
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
})
export default router父组件中的路由视图
<!-- src/views/DashboardView.vue -->
<template>
<div class="dashboard">
<!-- 侧边栏导航 -->
<aside class="sidebar">
<h2>仪表盘</h2>
<nav>
<router-link to="/dashboard">首页</router-link>
<router-link to="/dashboard/profile">个人资料</router-link>
<router-link to="/dashboard/settings">设置</router-link>
</nav>
</aside>
<!-- 主内容区,渲染子路由组件 -->
<main class="content">
<router-view />
</main>
</div>
</template>
<script setup lang="ts">
// Dashboard组件逻辑
</script>
<style scoped>
.dashboard {
display: flex;
height: 100vh;
}
.sidebar {
width: 200px;
background-color: #2c3e50;
color: white;
padding: 20px;
}
.content {
flex: 1;
padding: 20px;
background-color: #f5f5f5;
}
nav a {
display: block;
color: white;
text-decoration: none;
padding: 10px 0;
margin: 10px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
nav a.router-link-exact-active {
color: #42b983;
font-weight: bold;
}
</style>子路由组件
<!-- src/views/DashboardHomeView.vue -->
<template>
<div>
<h1>仪表盘首页</h1>
<p>欢迎来到仪表盘!</p>
</div>
</template>
<script setup lang="ts">
// DashboardHome组件逻辑
</script><!-- src/views/DashboardProfileView.vue -->
<template>
<div>
<h1>个人资料</h1>
<p>这里是您的个人资料页面。</p>
</div>
</template>
<script setup lang="ts">
// DashboardProfile组件逻辑
</script><!-- src/views/DashboardSettingsView.vue -->
<template>
<div>
<h1>设置</h1>
<p>这里是设置页面。</p>
</div>
</template>
<script setup lang="ts">
// DashboardSettings组件逻辑
</script>3. 嵌套路由的高级配置
多级嵌套路由
// src/router/index.ts
const routes: Array<RouteRecordRaw> = [
{
path: '/admin',
name: 'admin',
component: () => import('../views/AdminLayout.vue'),
children: [
{
path: '',
name: 'admin-home',
component: () => import('../views/AdminHomeView.vue')
},
{
path: 'users',
name: 'admin-users',
component: () => import('../views/AdminUsersLayout.vue'),
// 二级嵌套路由
children: [
{
path: '',
name: 'admin-users-list',
component: () => import('../views/AdminUsersListView.vue')
},
{
path: ':id',
name: 'admin-user-detail',
component: () => import('../views/AdminUserDetailView.vue')
},
{
path: ':id/edit',
name: 'admin-user-edit',
component: () => import('../views/AdminUserEditView.vue')
}
]
}
]
}
]动态嵌套路由
// src/router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
// 动态生成路由
function generateRoutes(): Array<RouteRecordRaw> {
const dynamicRoutes: Array<RouteRecordRaw> = [
{
path: '/dynamic',
name: 'dynamic',
component: () => import('../views/DynamicLayout.vue'),
children: [
{
path: 'page1',
name: 'dynamic-page1',
component: () => import('../views/DynamicPage1.vue')
},
{
path: 'page2',
name: 'dynamic-page2',
component: () => import('../views/DynamicPage2.vue')
}
]
}
]
// 根据权限动态添加路由
const hasPermission = true
if (hasPermission) {
dynamicRoutes[0].children?.push({
path: 'page3',
name: 'dynamic-page3',
component: () => import('../views/DynamicPage3.vue')
})
}
return dynamicRoutes
}
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'home',
component: () => import('../views/HomeView.vue')
},
// 合并动态生成的路由
...generateRoutes()
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
})4. 路由配置的高级技巧
1. 路由别名
const routes: Array<RouteRecordRaw> = [
{
path: '/home',
name: 'home',
component: HomeView,
// 路由别名,可以通过多个URL访问同一组件
alias: ['/', '/welcome']
}
]2. 路由重定向
const routes: Array<RouteRecordRaw> = [
{
path: '/',
// 重定向到home路由
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: HomeView
},
{
path: '/old-path',
// 重定向到新路由
redirect: { name: 'new-path' }
},
{
path: '/new-path',
name: 'new-path',
component: NewPathView
},
{
path: '/user/:id',
// 动态重定向
redirect: to => {
// to是路由对象,可以获取参数、查询等
return { path: `/profile/${to.params.id}` }
}
}
]3. 路由组件传参
const routes: Array<RouteRecordRaw> = [
{
path: '/user/:id',
name: 'user',
component: UserView,
// 路由组件传参,将路由参数作为props传递给组件
props: true
},
{
path: '/search',
name: 'search',
component: SearchView,
// 将查询参数作为props传递给组件
props: route => ({ query: route.query.q })
},
{
path: '/static',
name: 'static',
component: StaticView,
// 静态props
props: { staticProp: 'value' }
}
]4. 路由懒加载的分组
const routes: Array<RouteRecordRaw> = [
{
path: '/home',
name: 'home',
component: () => import('../views/HomeView.vue')
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue')
},
// 将多个路由组件打包到同一个chunk中
{
path: '/admin',
name: 'admin',
component: () => import(/* webpackChunkName: "admin" */ '../views/AdminView.vue')
},
{
path: '/admin/users',
name: 'admin-users',
component: () => import(/* webpackChunkName: "admin" */ '../views/AdminUsersView.vue')
}
]5. 组合式API中的路由使用
1. useRouter和useRoute
<script setup lang="ts">
import { useRouter, useRoute } from 'vue-router'
// 获取路由实例
const router = useRouter()
// 获取当前路由信息
const route = useRoute()
// 获取路由参数
const userId = route.params.id
// 获取查询参数
const query = route.query
// 获取路由元信息
const meta = route.meta
// 编程式导航
function navigateToHome() {
router.push('/home')
}
function navigateToUser(id: string) {
router.push({ name: 'user', params: { id } })
}
</script>2. 监听路由变化
<script setup lang="ts">
import { useRoute, watch } from 'vue-router'
const route = useRoute()
// 监听路由变化
watch(
() => route.params,
(newParams, oldParams) => {
// 处理路由参数变化
console.log('路由参数变化:', newParams, oldParams)
},
{ deep: true }
)
// 监听整个路由对象变化
watch(
() => route,
(newRoute, oldRoute) => {
// 处理路由变化
console.log('路由变化:', newRoute, oldRoute)
},
{ deep: true }
)
</script>📝 最佳实践
合理设计路由结构
- 路由结构应反映页面的层次结构
- 避免过深的嵌套路由(建议不超过3层)
- 使用模块化管理复杂路由
使用命名路由
- 优先使用命名路由进行导航
- 提高代码的可读性和可维护性
- 便于路由重构
实现路由懒加载
- 对所有路由组件使用懒加载
- 合理分组路由组件,优化加载性能
- 使用webpackChunkName注释进行代码分割
配置默认子路由
- 为父路由配置默认子路由
- 避免出现空白内容区域
- 提高用户体验
使用路由组件传参
- 优先使用props将路由参数传递给组件
- 使组件更独立,便于测试和复用
实现路由重定向
- 为旧路由配置重定向,确保链接可用性
- 使用动态重定向处理复杂场景
添加路由元信息
- 使用meta字段存储路由的附加信息
- 用于权限控制、菜单生成、页面标题等
使用组合式API
- 在Vue 3中优先使用useRouter和useRoute
- 与Composition API无缝配合
- 提高代码的可组合性
💡 常见问题与解决方案
嵌套路由不显示
- 检查父组件是否包含
<router-view> - 检查子路由路径是否正确
- 确保路由配置顺序正确
- 检查父组件是否包含
默认子路由不生效
- 检查默认子路由的path是否为空
- 确保默认子路由在children数组中
路由参数不更新
- 使用watch监听路由参数变化
- 避免在组件初始化时只获取一次参数
- 使用组合式API的watch函数
路由懒加载失败
- 检查动态import语法是否正确
- 确保构建工具支持ES模块
- 检查组件路径是否正确
路由重定向循环
- 避免路由重定向到自身或形成循环链
- 使用命名路由进行重定向
- 检查重定向逻辑
路由顺序问题
- 路由匹配是从上到下的,确保更具体的路由在前面
- 避免通配符路由(*)在前面
📚 进一步学习资源
🎯 课后练习
基础练习
- 创建一个包含嵌套路由的Vue 3应用
- 实现一个简单的后台管理系统布局
- 配置默认子路由和多级嵌套路由
进阶练习
- 实现路由别名和重定向
- 使用路由组件传参
- 配置路由懒加载的分组
实战练习
- 构建一个完整的后台管理系统路由结构
- 实现动态路由生成
- 使用组合式API处理路由
性能优化练习
- 分析路由懒加载的打包结果
- 优化路由组件的代码分割
- 测试不同路由配置的加载性能
通过本集的学习,你已经掌握了Vue Router 4.x的路由配置进阶技巧,包括嵌套路由的定义、配置、使用场景以及最佳实践。在实际项目中,合理设计和配置路由,能够构建出具有良好层次结构、性能优良的单页应用。下一集我们将深入学习编程式导航方法大全,进一步提升Vue 3路由系统的使用能力。