模式切换
Vue Router 4
Vue Router 是 Vue.js 官方的路由管理器,用于构建单页面应用(SPA)。Vue Router 4 是 Vue 3 的配套路由版本,提供更灵活的 API 和更好的 TypeScript 支持。
安装与基本配置
安装
bash
npm install vue-router@4
# 或
yarn add vue-router@4
基础路由配置
javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue')
},
{
path: '/about',
name: 'About',
component: () => import('@/views/About.vue')
}
]
const router = createRouter({
history: createWebHistory(), // 使用HTML5 history模式
routes
})
export default router
挂载到Vue应用
javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
核心功能
路由视图 <router-view>
vue
<!-- App.vue -->
<template>
<router-view></router-view> <!-- 路由匹配的组件将渲染在这里 -->
</template>
导航链接 <router-link>
vue
<template>
<router-link to="/">首页</router-link>
<router-link :to="{ name: 'About' }">关于</router-link>
</template>
编程式导航
javascript
import { useRouter } from 'vue-router'
// 在setup中使用
const router = useRouter()
// 跳转到指定路径
router.push('/about')
// 带参数跳转
router.push({ name: 'User', params: { id: 123 } })
// 替换当前路由(不记录历史)
router.replace('/login')
// 前进/后退
router.go(1) // 前进一步
router.go(-1) // 后退一步
动态路由
基本概念
动态路由允许在路径中使用变量部分,常用于显示基于ID的内容(如用户详情、产品页面等)。
配置动态路由
javascript
// router/index.js
const routes = [
{
path: '/user/:id', // :id 是动态参数
name: 'User',
component: () => import('@/views/User.vue')
},
{
path: '/product/:category/:id', // 多段动态参数
component: () => import('@/views/Product.vue')
}
]
获取动态参数
在目标组件中通过 useRoute()
获取参数:
vue
<!-- User.vue -->
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params.id) // 输出URL中的id值
</script>
高级匹配模式
模式 | 说明 | 示例 |
---|---|---|
:id | 基础动态段 | /user/123 |
:id(\\d+) | 只匹配数字 | /user/123 (不匹配/user/abc ) |
:chapters* | 匹配零个或多个 | /a/b/c 匹配 params: { chapters: ['a', 'b', 'c'] } |
:chapters+ | 匹配一个或多个 | 同上,但至少一个 |
/:pathMatch(.*)* | 404捕获路由 | 匹配所有未定义路径 |
响应参数变化
当从 /user/1
导航到 /user/2
时,同一组件实例会被复用,需要监听参数变化:
vue
<script setup>
import { watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
watch(
() => route.params.id,
(newId) => {
fetchUser(newId) // 参数变化时重新获取数据
}
)
</script>
最佳实践
参数验证:使用正则约束参数格式
javascriptpath: '/user/:id(\\d+)' // 只匹配数字ID
Props 解耦:通过
props: true
将参数作为组件 props 传递javascript{ path: '/user/:id', component: User, props: true // route.params 将作为 props 传入 }
嵌套路由
基本概念
嵌套路由允许在组件内部再嵌套子路由,形成多级路由结构(如后台管理系统的布局)。
配置嵌套路由
javascript
const routes = [
{
path: '/dashboard',
component: () => import('@/layouts/Dashboard.vue'),
children: [
{
path: '', // 默认子路由
component: () => import('@/views/DashboardHome.vue')
},
{
path: 'profile', // 匹配 /dashboard/profile
component: () => import('@/views/DashboardProfile.vue')
},
{
path: 'settings',
component: () => import('@/views/DashboardSettings.vue')
}
]
}
]
嵌套视图
父组件需包含 <router-view>
作为子路由出口:
vue
<!-- Dashboard.vue -->
<template>
<div>
<h1>Dashboard 布局</h1>
<nav>
<router-link to="/dashboard">首页</router-link>
<router-link to="/dashboard/profile">个人资料</router-link>
</nav>
<router-view></router-view> <!-- 子路由内容渲染在这里 -->
</div>
</template>
嵌套路由的路径行为
配置方式 | 实际路径 | 说明 |
---|---|---|
path: 'profile' | /dashboard/profile | 相对路径(推荐) |
path: '/profile' | /profile | 绝对路径(会跳出嵌套) |
嵌套路由的命名视图
支持多个命名视图的嵌套:
javascript
{
path: '/admin',
components: {
default: AdminLayout,
sidebar: AdminSidebar
},
children: [
{
path: 'users',
components: {
default: UserList,
sidebar: UserStats
}
}
]
}
最佳实践
布局提取:将公共布局抽离为父路由组件
默认子路由:始终为嵌套路由提供默认视图
路径命名:使用命名路由方便维护
javascript{ path: 'profile', name: 'DashboardProfile' // 全路径命名 }
动态嵌套路由
动态子路由
javascript
{
path: '/category/:category',
component: Category,
children: [
{
path: ':subcategory',
component: Subcategory
}
]
}
/category/books
→ 显示Category组件(无子内容)/category/books/fiction
→ 显示Category + Subcategory组件
捕获所有子路由
javascript
{
path: '/docs',
component: Docs,
children: [
{
path: ':pathMatch(.*)*', // 匹配所有/docs/下的路径
component: DocPage
}
]
}
导航守卫(路由拦截)
导航守卫是 Vue Router 的核心功能之一,允许您在路由导航过程中插入控制逻辑,实现权限验证、数据预加载、页面追踪等功能。
导航守卫类型
Vue Router 提供三类导航守卫:
类型 | 调用时机 | 使用场景 |
---|---|---|
全局守卫 | 所有路由切换 | 权限控制、日志记录 |
路由独享守卫 | 特定路由配置 | 路由级权限校验 |
组件内守卫 | 组件生命周期 | 组件级逻辑控制 |
全局守卫
router.beforeEach (全局前置守卫)
javascript
const router = createRouter({ /*...*/ })
router.beforeEach((to, from, next) => {
// to: 即将进入的路由
// from: 当前导航正要离开的路由
// next: 必须调用的函数
if (to.meta.requiresAuth && !isAuthenticated()) {
next('/login') // 重定向到登录页
} else {
next() // 放行
}
})
next() 的三种用法:
next()
: 正常放行next(false)
: 中断当前导航next('/path')
: 重定向到新路径
router.beforeResolve (全局解析守卫)
- 在导航被确认前,所有组件内守卫和异步路由组件被解析后调用
- 适合获取数据或执行动画前的最后检查
javascript
router.beforeResolve(async to => {
if (to.meta.requiresData) {
await fetchData(to.params.id)
}
})
router.afterEach (全局后置钩子)
- 导航已确认后调用,无法改变导航
- 适合日志记录、页面分析
javascript
router.afterEach((to, from) => {
sendToAnalytics(to.fullPath)
})
路由独享守卫
在路由配置中直接定义:
javascript
const routes = [
{
path: '/admin',
component: Admin,
beforeEnter: (to, from, next) => {
if (!isAdmin()) {
next('/forbidden')
} else {
next()
}
}
}
]
特点:
- 只在进入该路由时触发
- 比全局守卫优先级更高
组件内守卫
beforeRouteEnter
- 在渲染该组件的对应路由被验证前调用
- 不能访问组件实例 (
this
),因为组件还未创建
javascript
export default {
beforeRouteEnter(to, from, next) {
next(vm => {
// 通过回调访问组件实例
console.log(vm.$data)
})
}
}
beforeRouteUpdate
- 在当前路由改变但组件被复用时调用
- 可以访问组件实例 (
this
)
javascript
export default {
beforeRouteUpdate(to, from) {
this.fetchData(to.params.id) // 响应路由参数变化
}
}
beforeRouteLeave
- 在导航离开该组件的对应路由时调用
- 常用于防止用户误操作丢失数据
javascript
export default {
beforeRouteLeave(to, from, next) {
if (this.hasUnsavedChanges) {
if (confirm('有未保存的更改,确定离开吗?')) {
next()
} else {
next(false)
}
} else {
next()
}
}
}
完整导航解析流程
- 导航被触发
- 调用失活组件的
beforeRouteLeave
- 调用全局
beforeEach
- 在重用的组件里调用
beforeRouteUpdate
- 调用路由配置中的
beforeEnter
- 解析异步路由组件
- 调用激活组件的
beforeRouteEnter
- 调用全局
beforeResolve
- 导航被确认
- 调用全局
afterEach
- 触发 DOM 更新
- 调用
beforeRouteEnter
中传给next
的回调
实战案例
登录验证
javascript
// 全局前置守卫
router.beforeEach((to, from, next) => {
const isAuthRequired = to.matched.some(record => record.meta.requiresAuth)
const isAuthenticated = checkAuth() // 你的验证逻辑
if (isAuthRequired && !isAuthenticated) {
next({
path: '/login',
query: { redirect: to.fullPath } // 登录后重定向回原页面
})
} else {
next()
}
})
页面权限控制
javascript
// 路由配置
{
path: '/admin',
meta: {
requiresRole: 'admin'
}
}
// 全局守卫
router.beforeEach((to, from, next) => {
const requiredRole = to.meta.requiresRole
if (requiredRole && !hasRole(requiredRole)) {
next('/403') // 无权限页面
} else {
next()
}
})
动态标题设置
javascript
router.afterEach((to) => {
document.title = to.meta.title || '默认标题'
})
常见问题
如何避免无限重定向?
javascript
router.beforeEach((to, from, next) => {
if (to.path === '/login' && isAuthenticated()) {
next('/') // 已登录时访问/login则跳转首页
} else {
next()
}
})
如何获取组件实例?
javascript
beforeRouteEnter(to, from, next) {
next(vm => {
// vm 是组件实例
vm.loadData()
})
}
如何取消导航?
javascript
next(false) // 中断当前导航
最佳实践
- 权限验证:推荐在全局
beforeEach
中统一处理 - 数据预加载:使用
beforeRouteEnter
或beforeResolve
- 敏感操作确认:在
beforeRouteLeave
中提示用户 - 性能优化:避免在守卫中执行耗时操作
- 代码组织:将复杂守卫逻辑提取到单独文件
路由元信息
定义路由元信息
javascript
{
path: '/admin',
component: Admin,
meta: {
requiresAuth: true,
title: '管理后台'
}
}
使用元信息
javascript
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
// 权限校验逻辑
}
})
路由模式
模式 | 说明 | 配置方式 |
---|---|---|
History模式 | 干净的URL(需要服务器支持) | createWebHistory() |
Hash模式 | 带#的URL(兼容性好) | createWebHashHistory() |
Memory模式 | 无URL变化(SSR/测试用) | createMemoryHistory() |
javascript
import { createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory(), // 使用hash模式
routes
})
懒加载路由
javascript
// 使用动态import实现懒加载
{
path: '/about',
component: () => import('@/views/About.vue')
}
常见问题解决方案
路由重复导航错误
javascript
// 捕获重复导航错误
router.push('/').catch(err => {
if (err.name !== 'NavigationDuplicated') {
throw err
}
})
滚动行为控制
javascript
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition // 返回保存的位置
}
return { top: 0 } // 滚动到顶部
}
})
404页面处理
javascript
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/NotFound.vue')
}
完整示例
路由配置
javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue'),
meta: { title: '首页' }
},
{
path: '/user/:id',
name: 'User',
component: () => import('@/views/User.vue'),
props: true,
meta: { requiresAuth: true }
},
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/NotFound.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to, from, next) => {
document.title = to.meta.title || '默认标题'
next()
})
export default router
组件使用
vue
<!-- App.vue -->
<template>
<nav>
<router-link to="/">首页</router-link>
<router-link :to="{ name: 'User', params: { id: 123 } }">用户</router-link>
</nav>
<router-view></router-view>
</template>
总结
Vue Router 4 的核心功能包括:
- 声明式导航:
<router-link>
- 编程式导航:
router.push()
/replace()
- 动态路由:参数传递与获取
- 嵌套路由:多级路由视图
- 导航守卫:路由拦截与控制
- 路由懒加载:优化性能