路由配置是 Vue Router 的核心,它定义了 URL 路径与 Vue 组件之间的映射关系。本章将深入探讨路由配置的各种选项和高级用法。
一个基本的 Vue Router 配置包含一个路由数组,每个路由对象定义了路径与组件的映射关系。
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
// 定义路由组件(实际开发中应该导入具体的组件文件)
const Home = { template: '<div>首页</div>' }
const About = { template: '<div>关于我们</div>' }
// 定义路由配置
const routes = [
{
path: '/',
component: Home
},
{
path: '/about',
component: About
}
]
// 创建路由实例
const router = createRouter({
// 使用 HTML5 History 模式
history: createWebHistory(),
// 路由配置数组
routes
})
export default router
每个路由对象可以包含多个配置选项,下面是最常用的配置项:
| 配置项 | 类型 | 说明 | 示例 |
|---|---|---|---|
| path | string | 路由路径,支持动态参数和正则表达式 | '/user/:id' |
| component | Component | 路由组件(默认视图) | Home |
| name | string | 路由名称,用于编程式导航 | 'home' |
| components | Object | 命名视图组件映射 | { default: Home, sidebar: Sidebar } |
| redirect | string/Object/Function | 重定向到其他路由 | '/home' 或 { name: 'home' } |
| alias | string/Array | 路由别名 | '/homepage' |
| meta | Object | 路由元信息,用于权限控制等 | { requiresAuth: true } |
| props | boolean/Object/Function | 将路由参数作为 props 传递给组件 | true 或 { default: true } |
| beforeEnter | Function/Array | 路由独享的守卫 | 守卫函数 |
| children | Array | 嵌套路由配置 | 子路由数组 |
import { createRouter, createWebHistory } from 'vue-router'
// 导入组件
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import UserProfile from '../views/UserProfile.vue'
import UserPosts from '../views/UserPosts.vue'
import NotFound from '../views/NotFound.vue'
import DashboardLayout from '../layouts/Dashboard.vue'
import DashboardHome from '../views/dashboard/Home.vue'
import DashboardSettings from '../views/dashboard/Settings.vue'
const routes = [
// 基础路由
{
path: '/',
name: 'home',
component: Home,
meta: {
title: '首页',
requiresAuth: false
}
},
// 带别名的路由
{
path: '/about',
name: 'about',
component: About,
alias: '/about-us', // 访问 /about-us 也会显示 About 组件
meta: {
title: '关于我们',
requiresAuth: false
}
},
// 重定向
{
path: '/home',
redirect: '/' // 将 /home 重定向到 /
},
{
path: '/old-about',
redirect: { name: 'about' } // 命名路由重定向
},
{
path: '/legacy/:id',
redirect: to => {
// 函数式重定向,可以动态计算重定向目标
return { path: `/user/${to.params.id}` }
}
},
// 动态路由
{
path: '/user/:id',
name: 'user',
component: UserProfile,
props: true, // 将路由参数作为 props 传递
meta: {
requiresAuth: true,
title: '用户资料'
},
// 路由独享守卫
beforeEnter: (to, from) => {
// 检查用户权限等
if (!isValidUserId(to.params.id)) {
return { name: 'not-found' }
}
}
},
// 嵌套路由
{
path: '/dashboard',
component: DashboardLayout,
meta: { requiresAuth: true },
children: [
// 当 /dashboard 时,默认显示 DashboardHome
{
path: '',
name: 'dashboard',
component: DashboardHome,
meta: { title: '控制面板' }
},
{
path: 'settings',
name: 'dashboard.settings',
component: DashboardSettings,
meta: { title: '设置' }
},
// 嵌套的动态路由
{
path: 'user/:userId/posts/:postId',
name: 'user.post',
component: UserPosts,
props: route => ({
userId: parseInt(route.params.userId),
postId: parseInt(route.params.postId),
editMode: route.query.edit === 'true'
})
}
]
},
// 404 页面 - 通配符路由
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: NotFound,
meta: { title: '页面未找到' }
}
]
// 创建路由实例
const router = createRouter({
history: createWebHistory(),
routes,
// 全局配置
scrollBehavior(to, from, savedPosition) {
// 控制滚动行为
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
}
}
})
export default router
// 辅助函数
function isValidUserId(id) {
// 验证用户ID的逻辑
return /^\d+$/.test(id)
}
Vue Router 的路径语法非常灵活,支持多种匹配模式。
动态路由允许根据参数动态匹配路由,是最常用的路由功能之一。
const routes = [
// 基础动态路由
{
path: '/user/:id',
component: UserDetail
},
// 多个动态参数
{
path: '/category/:categoryId/product/:productId',
component: ProductDetail
},
// 可选参数
{
path: '/blog/:year?/:month?/:day?',
component: BlogArchive,
// 当所有参数都省略时,显示所有博客文章
},
// 带正则约束的参数
{
path: '/user/:id(\\d+)', // 只匹配数字ID
component: UserDetail
},
{
path: '/file/:name(.+)?', // 匹配文件名,包括扩展名
component: FileViewer
}
]
<!-- UserDetail.vue -->
<template>
<div>
<h2>用户详情</h2>
<p>用户ID: {{ userId }}</p>
<p>路由参数: {{ $route.params }}</p>
<p>查询参数: {{ $route.query }}</p>
</div>
</template>
<script>
// Options API
export default {
computed: {
userId() {
return this.$route.params.id
}
},
mounted() {
console.log('路由参数:', this.$route.params)
console.log('查询参数:', this.$route.query)
}
}
</script>
<!-- Composition API -->
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
const userId = route.params.id
// 监听参数变化
import { watch } from 'vue'
watch(
() => route.params.id,
(newId) => {
console.log('用户ID变化:', newId)
// 重新加载用户数据
fetchUserData(newId)
}
)
</script>
通过配置 props 选项,可以将路由参数作为组件的 props 传递,使组件更易于测试和复用。
const routes = [
// 1. 布尔模式:将 params 转换为 props
{
path: '/user/:id',
component: UserDetail,
props: true // 将 route.params.id 作为 id prop 传递
},
// 2. 对象模式:静态 props
{
path: '/about',
component: About,
props: {
showHeader: true,
theme: 'dark'
}
},
// 3. 函数模式:动态计算 props
{
path: '/search',
component: SearchResults,
props: (route) => ({
query: route.query.q || '',
page: parseInt(route.query.page) || 1,
sortBy: route.query.sort || 'relevance'
})
},
// 4. 命名视图的 props 配置
{
path: '/dashboard',
components: {
default: Dashboard,
sidebar: Sidebar
},
props: {
default: true, // 为默认视图启用 props
sidebar: (route) => ({
activeTab: route.query.tab || 'overview'
})
}
}
]
<!-- UserDetail.vue -->
<template>
<div>
<h2>用户 {{ id }} 的详情</h2>
<!-- 直接使用 props -->
</div>
</template>
<script>
// Options API
export default {
props: {
id: {
type: [String, Number],
required: true
}
}
}
</script>
<!-- Composition API -->
<script setup>
// 使用 defineProps 接收 props
const props = defineProps({
id: {
type: [String, Number],
required: true
}
})
console.log('用户ID:', props.id)
</script>
嵌套路由允许在组件内部嵌套其他路由,用于构建复杂的页面布局。
const routes = [
{
path: '/dashboard',
component: DashboardLayout,
meta: { requiresAuth: true },
children: [
// 空路径子路由 - 当访问 /dashboard 时显示
{
path: '',
name: 'dashboard.home',
component: DashboardHome,
meta: { title: '控制面板' }
},
// 相对路径子路由 - 实际路径为 /dashboard/profile
{
path: 'profile',
name: 'dashboard.profile',
component: UserProfile,
meta: { title: '个人资料' }
},
// 绝对路径子路由 - 实际路径为 /settings
{
path: '/settings',
name: 'settings',
component: Settings,
meta: { title: '设置' }
},
// 嵌套的子路由 - 实际路径为 /dashboard/posts
{
path: 'posts',
component: PostsLayout,
children: [
{
path: '',
component: PostsList,
meta: { title: '文章列表' }
},
{
path: ':postId',
component: PostDetail,
props: true,
meta: { title: '文章详情' }
},
{
path: 'create',
component: CreatePost,
meta: { title: '创建文章' }
}
]
}
]
}
]
命名视图允许在同一路由下显示多个组件,适用于复杂的布局需求。
<!-- App.vue 模板 -->
<template>
<div id="app">
<router-view name="header"></router-view>
<main>
<router-view></router-view> <!-- 默认视图 -->
</main>
<router-view name="sidebar"></router-view>
<router-view name="footer"></router-view>
</div>
</template>
<!-- 路由配置 -->
<script>
const routes = [
{
path: '/',
// 注意:这里是 components(复数),不是 component
components: {
default: Home, // 对应 <router-view>
header: AppHeader, // 对应 <router-view name="header">
sidebar: AppSidebar, // 对应 <router-view name="sidebar">
footer: AppFooter // 对应 <router-view name="footer">
},
meta: { title: '首页' }
},
{
path: '/dashboard',
components: {
default: Dashboard,
header: DashboardHeader,
sidebar: DashboardSidebar,
footer: DashboardFooter
},
meta: { requiresAuth: true }
},
{
path: '/login',
// 只覆盖部分命名视图
components: {
default: Login,
header: null, // 不显示 header
footer: null // 不显示 footer
}
}
]
</script>
const routes = [
// 1. 字符串重定向
{
path: '/home',
redirect: '/' // 将 /home 重定向到根路径
},
// 2. 命名路由重定向
{
path: '/old-user/:id',
redirect: {
name: 'user', // 重定向到名为 'user' 的路由
params: { id: 'new-id' } // 可以修改参数
}
},
// 3. 函数式重定向(最灵活)
{
path: '/legacy/:path*',
redirect: to => {
// 动态计算重定向目标
const { params, query } = to
if (params.path === 'about') {
return { name: 'about' }
} else if (params.path === 'contact') {
return { path: '/contact', query: { from: 'legacy' } }
} else {
// 重定向到 404
return { name: 'not-found' }
}
}
},
// 4. 相对重定向
{
path: '/users/:id',
children: [
{
path: '',
component: UserProfile
},
{
path: 'posts',
redirect: 'posts/list' // 相对路径,重定向到 /users/:id/posts/list
},
{
path: 'posts/list',
component: UserPosts
}
]
}
]
const routes = [
// 单个别名
{
path: '/about',
component: About,
alias: '/about-us' // 访问 /about-us 也会显示 About 组件
},
// 多个别名
{
path: '/home',
component: Home,
alias: ['/index', '/main', '/welcome'] // 多个别名
},
// 嵌套路由的别名
{
path: '/user/:id',
component: UserLayout,
children: [
{
path: 'profile',
component: UserProfile,
alias: ['/u/:id', '/member/:id'] // 别名可以包含参数
}
]
},
// 绝对别名
{
path: '/admin',
component: Admin,
alias: '/administrator' // 绝对路径别名
}
]
对于大型项目,建议将路由配置拆分为多个模块,便于管理和维护。
// router/index.js - 主路由文件
import { createRouter, createWebHistory } from 'vue-router'
// 导入模块化路由配置
import authRoutes from './routes/auth'
import adminRoutes from './routes/admin'
import userRoutes from './routes/user'
import blogRoutes from './routes/blog'
// 基础路由
const baseRoutes = [
{
path: '/',
name: 'home',
component: () => import('@/views/Home.vue'),
meta: { title: '首页' }
},
{
path: '/about',
name: 'about',
component: () => import('@/views/About.vue'),
meta: { title: '关于我们' }
}
]
// 合并所有路由
const routes = [
...baseRoutes,
...authRoutes,
...adminRoutes,
...userRoutes,
...blogRoutes,
// 404 路由放在最后
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('@/views/NotFound.vue'),
meta: { title: '页面未找到' }
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
// router/routes/auth.js - 认证相关路由
const authRoutes = [
{
path: '/login',
name: 'login',
component: () => import('@/views/auth/Login.vue'),
meta: {
title: '登录',
guestOnly: true // 仅允许未登录用户访问
}
},
{
path: '/register',
name: 'register',
component: () => import('@/views/auth/Register.vue'),
meta: {
title: '注册',
guestOnly: true
}
},
{
path: '/forgot-password',
name: 'forgot-password',
component: () => import('@/views/auth/ForgotPassword.vue'),
meta: { title: '忘记密码' }
},
{
path: '/reset-password/:token',
name: 'reset-password',
component: () => import('@/views/auth/ResetPassword.vue'),
props: true,
meta: { title: '重置密码' }
}
]
export default authRoutes
// router/types.ts - 定义路由元信息类型
import 'vue-router'
declare module 'vue-router' {
interface RouteMeta {
// 页面标题
title?: string
// 是否需要登录
requiresAuth?: boolean
// 仅允许未登录用户访问
guestOnly?: boolean
// 允许访问的角色
roles?: string[]
// 是否保持 alive
keepAlive?: boolean
// 面包屑
breadcrumb?: string | ((route: RouteLocationNormalized) => string)
// 页面图标
icon?: string
}
}
// router/index.ts - 使用类型检查的路由配置
import { RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/dashboard',
name: 'dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: {
title: '控制面板',
requiresAuth: true,
roles: ['admin', 'editor'],
icon: 'dashboard'
}
}
// TypeScript 会检查 meta 属性的类型
]
// 在应用运行时动态添加路由
import { useRouter } from 'vue-router'
const router = useRouter()
// 添加单个路由
router.addRoute({
path: '/new-page',
component: () => import('@/views/NewPage.vue'),
meta: { title: '新页面' }
})
// 添加嵌套路由
router.addRoute('dashboard', {
path: 'analytics',
component: () => import('@/views/dashboard/Analytics.vue'),
meta: { title: '数据分析' }
})
// 删除路由
const removeRoute = router.addRoute({
path: '/temp',
component: () => import('@/views/Temp.vue')
})
// 稍后删除
removeRoute()
// 或者通过名称删除
router.removeRoute('temp-route')
// 检查路由是否存在
const hasRoute = router.hasRoute('dashboard')
// 获取所有路由记录
const routes = router.getRoutes()
console.log('所有路由:', routes)
路由配置演示中...
Vue Router 的路由配置提供了丰富的选项和灵活的语法,可以满足各种复杂的路由需求。通过合理配置路由,可以构建出结构清晰、易于维护的单页面应用。
关键要点回顾:
合理运用这些配置技巧,可以让你的 Vue 应用拥有更加强大和灵活的路由功能。