Vue3 路由
一、核心概念
1. 什么是路由?
路由是单页面应用(SPA)的核心机制,通过管理 URL 与组件的映射关系,实现不刷新页面切换视图的效果。
Vue Router 是 Vue 官方路由解决方案,主要功能包括:
-
嵌套路由映射
-
动态路由匹配
-
模块化的路由配置
-
导航控制(编程式导航、导航守卫)
-
自动的 CSS 类链接激活
-
滚动行为控制
2. 路由模式对比
模式 | URL 示例 | 原理 | 服务器配置要求 |
---|---|---|---|
Hash 模式 | http://site.com/#/about | 使用 URL hash(#后的部分) | 无需特殊配置 |
History 模式 | http://site.com/about | 依赖 HTML5 History API | 需要服务端支持 |
二、基础配置
1. 安装与初始化
npm install vue-router@4
// 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(), // 使用history模式routes
})export default router
2. 挂载到Vue实例
// 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')
三、路由视图与导航
1. 路由出口
在布局组件中使用 <router-view>
作为组件渲染容器:
<!-- App.vue -->
<template><nav><router-link to="/">首页</router-link><router-link :to="{ name: 'About' }">关于</router-link></nav><!-- 路由匹配的组件将渲染在这里 --><router-view></router-view>
</template>
2. 导航方式对比
方式 | 代码示例 | 特点 |
---|---|---|
声明式导航 | <router-link to="/about"> | 自动处理激活状态 |
编程式导航 | router.push('/about') 或 router.push({ name: 'About' }) | 适合逻辑触发跳转 |
替换当前路由 | router.replace('/login') | 不产生历史记录 |
前进/后退 | router.go(1) 或 router.go(-1) | 类似浏览器历史操作 |
四、动态路由与参数传递
1. 动态路径参数
{path: '/user/:id',name: 'User',component: () => import('@/views/User.vue'),props: true // 启用props接收参数
}
2. 参数获取方式
在目标组件中获取参数:
<script setup>
import { useRoute } from 'vue-router'const route = useRoute()// 方式1:通过路由对象
console.log(route.params.id)// 方式2:通过props(需配置props: true)
defineProps({id: String
})
</script>
3. 参数匹配规则
// 限定数字ID
path: '/user/:id(\\d+)'// 可选参数
path: '/search/:keyword?'
五、导航守卫
1. 守卫类型
守卫类型 | 执行时机 | 使用场景 |
---|---|---|
全局前置守卫 | 路由跳转前 | 权限验证、登录检查 |
全局解析守卫 | 导航被确认前 | 数据预加载 |
全局后置钩子 | 导航完成之后 | 页面分析统计 |
路由独享守卫 | 进入特定路由前 | 路由级别权限控制 |
组件内守卫 | 组件生命周期特定阶段 | 组件进入/离开时的操作 |
2. 典型应用
// 全局前置守卫
router.beforeEach((to, from, next) => {const isAuthenticated = localStorage.getItem('token')if (to.meta.requiresAuth && !isAuthenticated) {next({ name: 'Login' })} else {next()}
})// 路由独享守卫
{path: '/admin',component: Admin,beforeEnter: (to, from, next) => {// 管理员权限验证}
}// 组件内守卫
onBeforeRouteLeave((to, from, next) => {if (formDataChanged && !confirm('数据未保存,确定离开?')) {next(false)} else {next()}
})
六、嵌套路由
1. 配置方式
{path: '/dashboard',component: DashboardLayout,children: [{path: '', // 默认子路由component: DashboardHome},{path: 'settings',component: DashboardSettings}]
}
2. 视图结构
<!-- DashboardLayout.vue -->
<template><div class="dashboard"><sidebar /><div class="content"><router-view></router-view> <!-- 子路由组件在此渲染 --></div></div>
</template>
七、高级功能
1. 路由懒加载
component: () => import('./views/HeavyComponent.vue')
2. 滚动行为控制
const router = createRouter({scrollBehavior(to, from, savedPosition) {if (savedPosition) {return savedPosition} else if (to.hash) {return { el: to.hash }} else {return { top: 0 }}}
})
3. 路由元信息
{path: '/admin',meta: {requiresAuth: true,transition: 'slide-left'}
}
八、最佳实践
-
路由分层管理
src/
├── router/
│ ├── index.js # 主路由配置
│ ├── authRoutes.js # 认证相关路由
│ └── adminRoutes.js # 管理后台路由
-
动态路由加载
// 根据权限动态添加路由
function setupRoutes(userRole) {const baseRoutes = [...]const adminRoutes = [...]if (userRole === 'admin') {router.addRoute(adminRoutes)}
}
-
路由组件缓存
<router-view v-slot="{ Component }"><keep-alive><component :is="Component" /></keep-alive>
</router-view>
-
类型安全(TypeScript)
declare module 'vue-router' {interface RouteMeta {requiresAuth?: booleantransition?: string}
}
九、常见问题解决方案
Q1: History模式刷新404
# Nginx配置
location / {try_files $uri $uri/ /index.html;
}
Q2: 路由重复导航警告
// 封装安全的导航方法
function safePush(path) {if (route.path !== path) {router.push(path)}
}
Q3: 路由过渡动画
<router-view v-slot="{ Component }"><transition name="fade" mode="out-in"><component :is="Component" /></transition>
</router-view>
Q4: 多级路由缓存
<router-view v-slot="{ Component, route }"><keep-alive :include="cachedViews"><component :is="Component" :key="route.fullPath" /></keep-alive>
</router-view>