您的位置:首页 > 路由器知识路由器知识
2023最新VueRouter3.x完全指南:从入门到精通的路由管理手册
2026-06-03人已围观
.active {
color: red;
font-weight: bold;
border-bottom: 2px solid red;
}
2023最新Vue Router 3.x完全指南:从入门到精通的路由管理手册
一、为什么需要Vue Router?
想象你正在逛一家超级商场(你的单页应用),每个店铺就是一个组件。没有路由系统的话,你每次换店铺都得重新进一次商场大门(页面刷新)。而Vue Router就像商场里的指示牌和导航员,让你在不同店铺间自由穿梭,却不用每次都重新进商场——这就是单页应用(SPA)的核心优势:无刷新页面切换。
二、安装与基础配置
2.1 安装Vue Router
npm安装(推荐):
```bash
npm install vue-router@3.x --save
```
yarn安装:
```bash
yarn add vue-router@3.x
```
如果你使用vue-cli创建项目,可以在初始化时直接勾选"Router"选项,脚手架会自动帮你配置好基础路由结构。
2.2 基础路由配置
在src目录下创建`router`文件夹,新建`index.js`文件:
```javascript
import Vue from 'vue'
import Router from 'vue-router'
// 导入组件
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
// 安装路由插件
Vue.use(Router)
// 定义路由规则
const routes = [
{
path: '/', // URL路径
name: 'Home', // 路由名称(可选)
component: Home // 对应的组件
},
{
path: '/about',
name: 'About',
component: About
}
]
// 创建路由实例
const router = new Router({
mode: 'history', // 路由模式:history或hash
routes // 路由规则数组
})
export default router
```
然后在`main.js`中引入并使用路由:
```javascript
import Vue from 'vue'
import App from './App.vue'
import router from './router' // 引入路由实例
new Vue({
router, // 注入路由
render: h => h(App)
}).$mount('app')
```
三、路由导航与视图
3.1 声明式导航:`
```vue
```
`
- 自动添加激活状态的class(默认`router-link-active`)
- 避免整页刷新
- 支持各种高级功能(如动画、延迟加载)
你可以自定义激活样式:
```vue
.active {
color: red;
font-weight: bold;
border-bottom: 2px solid red;
}
```
3.2 编程式导航:`$router.push()`
在JavaScript代码中实现导航,就像你在App里点击按钮跳转到新页面:
```javascript
// 在组件方法中
methods: {
goToAbout() {
// 字符串路径
this.$router.push('/about')
// 命名路由 + 参数
this.$router.push({ name: 'About', params: { id: 123 } })
// 带查询参数,变成 /about?plan=private
this.$router.push({ path: '/about', query: { plan: 'private' } })
}
}
```
其他常用导航方法:
```javascript
// 替换当前历史记录(无法回退到上一页)
this.$router.replace('/about')
// 前进或后退
this.$router.go(-1) // 后退一页,类似浏览器的"后退"按钮
this.$router.go(1) // 前进一页
this.$router.go(0) // 刷新当前页
```
3.3 路由视图:`
`
```vue
```
四、动态路由匹配
4.1 基本用法
假设你有一个用户详情页,URL需要根据用户ID变化,比如`/user/1`、`/user/2`,这时就需要动态路由参数:
```javascript
// 路由配置
{
path: '/user/:id', // :id 就是动态参数
name: 'User',
component: User
}
```
在组件中获取参数:
```javascript
export default {
mounted() {
// 通过 this.$route.params 获取参数
console.log('用户ID:', this.$route.params.id)
}
}
```
你可以在路径中设置多个参数:
```javascript
{
path: '/user/:username/post/:postId',
component: UserPost
}
```
访问`/user/john/post/123`时,`$route.params`会是`{ username: 'john', postId: '123' }`。
4.2 响应路由参数变化
当从`/user/1`跳转到`/user/2`时,Vue会复用User组件(性能优化),这意味着组件的生命周期钩子(如`created`、`mounted`)不会重新执行。这就像你在微信里切换聊天窗口,聊天界面不会重新创建,但内容会更新。
有两种方法可以监听参数变化:
方法一:watch监听$route
```javascript
export default {
watch: {
'$route'(to, from) {
// to: 目标路由对象
// from: 源路由对象
this.loadUserData(to.params.id)
}
},
methods: {
loadUserData(userId) {
// 加载用户数据
}
}
}
```
方法二:导航守卫 beforeRouteUpdate
```javascript
export default {
beforeRouteUpdate(to, from, next) {
// 在路由更新前执行
this.loadUserData(to.params.id)
next() // 必须调用next()才能继续导航
}
}
```
4.3 参数校验
可以用正则表达式约束参数格式,比如只允许数字ID:
```javascript
{
// 只匹配数字ID
path: '/user/:id(\\d+)',
component: User
}
```
五、路由参数传递
5.1 动态路由参数(params)
适合传递重要参数(如ID),参数会作为URL的一部分:
```javascript
// 导航
this.$router.push({ name: 'User', params: { id: 123 } })
// 路由配置
{
path: '/user/:id',
name: 'User',
component: User
}
// 组件中获取
this.$route.params.id // "123"
```
5.2 查询参数(query)
适合传递非必需参数(如筛选条件),参数会以`?key=value`形式附加在URL后:
```javascript
// 导航
this.$router.push({ path: '/search', query: { keyword: 'vue', page: 1 } })
// 组件中获取
this.$route.query.keyword // "vue"
this.$route.query.page // "1"
```
5.3 props传参(推荐)
为了让组件更灵活复用,建议通过props接收路由参数,而不是直接使用`$route.params`:
路由配置:
```javascript
{
path: '/user/:id',
name: 'User',
component: User,
props: true // 启用props传参
}
```
组件中使用:
```vue
export default {
props: ['id'], // 直接接收id作为prop
mounted() {
console.log(this.id) // 不需要this.$route.params.id了
}
}
```
更高级的用法:函数式props,可以转换参数类型或组合参数:
```javascript
{
path: '/user/:id',
component: User,
props: route => ({
id: Number(route.params.id), // 转换为数字类型
fullPath: route.fullPath // 附加其他信息
})
}
```
六、嵌套路由
就像俄罗斯套娃,路由也可以嵌套。比如在Dashboard页面里,还有统计、设置等子页面:
```javascript
const routes = [
{
path: '/dashboard',
component: Dashboard,
children: [
{
// 当 /dashboard/stats 匹配成功
path: 'stats',
component: DashboardStats
},
{
// 当 /dashboard/settings 匹配成功
path: 'settings',
component: DashboardSettings
},
{
// 当 /dashboard 匹配成功,默认显示
path: '',
component: DashboardHome
}
]
}
]
```
在Dashboard组件中需要添加`
```vue
仪表盘
```
七、路由守卫
路由守卫就像保安,在你进入或离开某个区域(路由)时进行检查。常见场景:登录验证、权限控制。
7.1 全局守卫
在`router/index.js`中定义,对所有路由生效:
```javascript
// 全局前置守卫
router.beforeEach((to, from, next) => {
// to: 要去的路由
// from: 来自的路由
// next: 放行函数
// 检查是否需要登录
if (to.meta.requiresAuth && !isLogin()) {
// 未登录,重定向到登录页
next({ name: 'Login', query: { redirect: to.fullPath } })
} else {
// 已登录,放行
next()
}
})
// 全局后置钩子(没有next参数)
router.afterEach((to, from) => {
// 可以在这里修改页面标题
document.title = to.meta.title || '默认标题'
})
```
7.2 路由独享守卫
在路由配置中定义,只对当前路由生效:
```javascript
{
path: '/admin',
component: Admin,
beforeEnter: (to, from, next) => {
// 检查是否为管理员
if (userRole !== 'admin') {
next('/403') // 不是管理员,跳转到403页面
} else {
next() // 是管理员,放行
}
}
}
```
7.3 组件内守卫
在组件内部定义,控制组件的进入和离开:
```javascript
export default {
// 进入组件前
beforeRouteEnter(to, from, next) {
// 此时组件实例还未创建,不能使用this
next(vm => {
// vm就是组件实例
vm.loadData()
})
},
// 路由更新时(动态参数变化)
beforeRouteUpdate(to, from, next) {
this.loadData(to.params.id)
next()
},
// 离开组件时
beforeRouteLeave(to, from, next) {
// 询问用户是否保存修改
if (this.hasUnsavedChanges) {
if (confirm('有未保存的修改,确定要离开吗?')) {
next()
} else {
next(false) // 取消导航
}
} else {
next()
}
}
}
```
八、路由模式
Vue Router提供两种主要路由模式:
8.1 Hash模式(默认)
URL中带有``,如`http://example.com//user/1`。后面的内容不会发送到服务器,兼容性好(支持所有浏览器)。
```javascript
const router = new Router({
mode: 'hash', // 默认值,可以省略
routes
})
```
8.2 History模式
URL中没有``,如`http://example.com/user/1`,更美观但需要服务器支持。
```javascript
const router = new Router({
mode: 'history',
routes
})
```
服务器配置:
- Nginx:
```nginx
location / {
try_files $uri $uri/ /index.html;
}
```
- Apache:
```apache
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
```
九、路由过渡动画
给路由切换添加动画,提升用户体验:
```vue
/ 进入动画 /
.fade-enter {
opacity: 0;
transform: translateX(20px);
}
.fade-enter-active {
transition: all 0.3s ease;
}
/ 离开动画 /
.fade-leave-active {
transition: all 0.3s ease;
opacity: 0;
transform: translateX(-20px);
}
```
你还可以为不同路由设置不同动画:
```vue
export default {
data() {
return {
transitionName: 'fade'
}
},
watch: {
'$route'(to, from) {
// 根据路由深度决定动画方向
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
this.transitionName = toDepth > fromDepth ? 'slide-left' : 'slide-right'
}
}
}
```
十、数据获取
在路由组件中获取数据有两种常见方式:
10.1 导航完成后获取
先导航到新页面,再在组件的`created`钩子中获取数据,适合数据量小的情况:
```javascript
export default {
data() {
return {
user: null,
loading: false
}
},
created() {
// 导航完成后开始获取数据
this.loading = true
this.fetchUser()
},
watch: {
// 监听路由变化,重新获取数据
'$route': 'fetchUser'
},
methods: {
fetchUser() {
this.loading = true
fetch(`/api/user/${this.$route.params.id}`)
.then(res => res.json())
.then(data => {
this.user = data
this.loading = false
})
}
}
}
```
10.2 导航完成前获取
在导航守卫中获取数据,数据加载完成后再导航,适合数据量较大的情况:
```javascript
export default {
data() {
return {
user: null
}
},
beforeRouteEnter(to, from, next) {
// 在导航进入前获取数据
fetch(`/api/user/${to.params.id}`)
.then(res => res.json())
.then(user => {
// 将数据传递给组件实例
next(vm => {
vm.user = user
})
})
},
beforeRouteUpdate(to, from, next) {
// 参数变化时重新获取数据
this.user = null
fetch(`/api/user/${to.params.id}`)
.then(res => res.json())
.then(user => {
this.user = user
next()
})
}
}
```
十一、性能优化
11.1 路由懒加载
像快递分批发货一样,只在需要时才加载路由组件,减小初始加载体积:
```javascript
// 非懒加载
import Home from '@/views/Home.vue'
// 懒加载
const Home = () => import('@/views/Home.vue')
// 路由配置
const routes = [
{
path: '/',
name: 'Home',
component: Home // 现在是懒加载组件
}
]
```
更高级的写法:按组分包,把多个组件打包到同一个文件:
```javascript
const Home = () => import(/ webpackChunkName: "home" / '@/views/Home.vue')
const About = () => import(/ webpackChunkName: "home" / '@/views/About.vue')
```
11.2 组件缓存
使用`
```vue
```
高级用法:
```vue
```
被缓存的组件会触发`activated`和`deactivated`生命周期钩子:
```javascript
export default {
activated() {
// 组件被激活时调用
console.log('组件被缓存后激活')
},
deactivated() {
// 组件被缓存后失活时调用
console.log('组件被缓存后失活')
}
}
```
十二、常见问题解决
12.1 点击相同路由报错
问题:频繁点击相同导航链接,控制台报错 "Avoided redundant navigation to current location"
解决方案:重写Vue Router的push方法,全局处理错误:
```javascript
// 在router/index.js中
import Router from 'vue-router'
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
```
12.2 路由参数变化页面不更新
问题:从`/user/1`跳转到`/user/2`,页面内容没有更新
原因:Vue Router复用了组件实例,生命周期钩子不会重新执行
解决方案:
- 使用watch监听路由变化(见4.2节)
- 使用导航守卫beforeRouteUpdate(见4.2节)
- 给`
12.3 History模式刷新404
问题:History模式下,直接访问二级路由(如`/user/1`)刷新后404
原因:服务器没有正确配置,无法将所有路由指向index.html
解决方案:配置服务器(见8.2节)
12.4 路由守卫无限循环
问题:在全局守卫中使用`next('/login')`导致无限循环
原因:登录页也需要登录验证,形成死循环
解决方案:排除登录页:
```javascript
router.beforeEach((to, from, next) => {
const isLogin = localStorage.getItem('token')
// 如果需要登录且未登录,并且目标不是登录页
if (to.meta.requiresAuth && !isLogin && to.name !== 'Login') {
next({ name: 'Login' })
} else {
next()
}
})
```
12.5 路由动画不生效
问题:添加了过渡动画但没有效果
解决方案:
- 确保`
- 检查动画CSS类名是否正确(与transition的name属性对应)
- 确认路由切换时组件确实被重新渲染(或使用`:key`强制刷新)
十三、新手避坑清单
1. 不要在created/mounted中直接使用`$route.params`:参数变化时不会重新执行这些钩子
2. 使用命名路由代替硬编码路径:`this.$router.push({ name: 'User', params: { id: 1 } })`比`this.$router.push('/user/1')`更易维护
3. params参数不要在path中使用:`router.push({ path: '/user', params: { id: 1 } })`会忽略params
4. History模式需要服务器配置:开发环境没问题,部署到生产环境会404
5. 避免嵌套路由路径重复:子路由path不要以`/`开头,否则会被当作根路由
6. 动态路由参数默认是字符串:需要时记得转换类型(如`Number(this.$route.params.id)`)
7. 路由守卫必须调用next():否则导航会被卡住
8. 不要在beforeRouteEnter中使用this:此时组件实例还未创建
9. keep-alive会缓存组件状态:包含表单输入等临时数据,需要时在activated中重置
10. 路由懒加载不要过度拆分:每个组件一个chunk会导致太多网络请求
十四、实用小技巧
1. 路由元信息:给路由添加额外信息,用于权限控制、页面标题等
```javascript
{
path: '/admin',
component: Admin,
meta: {
requiresAuth: true, // 需要登录
roles: ['admin'], // 角色限制
title: '管理后台' // 页面标题
}
}
```
2. 滚动行为:控制路由切换时页面滚动位置
```javascript
const router = new Router({
mode: 'history',
routes,
scrollBehavior(to, from, savedPosition) {
// 返回savedPosition,在按下 后退/前进 按钮时,会像浏览器的原生表现那样
if (savedPosition) {
return savedPosition
} else {
// 滚动到顶部
return { x: 0, y: 0 }
}
}
})
```
3. 路由别名:给路由设置多个访问路径
```javascript
{
path: '/home',
name: 'Home',
component: Home,
alias: ['/index', '/main'] // 可以通过/index或/main访问Home组件
}
```
4. 路由重定向:将旧路径重定向到新路径
```javascript
{
path: '/old-path',
redirect: '/new-path' // 直接重定向
}
// 或更灵活的函数形式
{
path: '/search',
redirect: to => {
return { path: '/query', query: { q: to.query.keyword } }
}
}
```
5. 动态添加路由:用于权限控制,根据用户角色动态生成路由
```javascript
// 动态添加路由
router.addRoute({
path: '/admin',
component: Admin
})
// 添加子路由
router.addRoute('parentRouteName', {
path: 'child',
component: Child
})
// 删除路由
const removeRoute = router.addRoute(...)
removeRoute() // 调用返回的函数删除路由
```
6. 路由组件复用策略:通过`beforeRouteUpdate`优化数据加载
```javascript
export default {
data() {
return {
userData: null
}
},
async beforeRouteUpdate(to, from) {
// 显示加载状态
this.loading = true
// 取消之前的请求(如果需要)
if (this.cancelToken) {
this.cancelToken.cancel()
}
// 创建新的取消令牌
this.cancelToken = axios.CancelToken.source()
try {
// 获取新数据
this.userData = await getUserData(to.params.id, {
cancelToken: this.cancelToken.token
})
} catch (err) {
if (!axios.isCancel(err)) {
console.error('数据加载失败', err)
}
} finally {
this.loading = false
}
}
}
```
7. 全局路由错误处理:捕获路由跳转错误
```javascript
// 全局路由错误处理
router.onError(error => {
console.error('路由错误:', error)
// 处理懒加载失败等错误
if (error.type === 'missing') {
// 重定向到404页面
router.push('/404')
}
})
```
8. 查询参数格式化:统一处理查询参数的类型转换
```javascript
export default {
computed: {
page() {
// 确保page参数是数字,默认为1
return Number(this.$route.query.page) || 1
},
sort() {
// 限定排序方式
const validSorts = ['asc', 'desc']
return validSorts.includes(this.$route.query.sort)
? this.$route.query.sort
: 'asc'
}
}
}
```
9. 路由切换时保存表单数据:结合keep-alive和localStorage
```javascript
export default {
data() {
return {
formData: {
name: '',
email: ''
}
}
},
activated() {
// 从localStorage恢复数据
const saved = localStorage.getItem('formDraft')
if (saved) {
this.formData = JSON.parse(saved)
}
},
deactivated() {
// 保存到localStorage
localStorage.setItem('formDraft', JSON.stringify(this.formData))
},
beforeUnmount() {
// 组件销毁时清除
localStorage.removeItem('formDraft')
}
}
```
10. 使用路由命名视图:在同一页面展示多个组件
```javascript
// 路由配置
{
path: '/dashboard',
components: {
default: Dashboard,
sidebar: Sidebar,
header: Header
}
}
// 模板中
```
十五、长期使用体验
使用Vue Router开发大型应用一年多后,我总结出以下几点经验:
1. 路由设计要提前规划:特别是嵌套路由结构,后期调整成本高。建议画一张路由结构图,明确父子关系和参数传递方式。
2. 权限控制集中处理:将权限逻辑放在全局守卫中,配合路由元信息,使代码更清晰。例如:
```javascript
// 权限检查函数
function checkPermission(route, userRoles) {
if (!route.meta.roles) return true // 不需要权限
return route.meta.roles.some(role => userRoles.includes(role))
}
// 全局守卫中使用
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isLogin()) {
next({ name: 'Login' })
} else if (!checkPermission(to, currentUser.roles)) {
next({ name: 'Forbidden' })
} else {
next()
}
})
```
3. 路由参数尽量简单:复杂的状态管理应该交给Vuex/Pinia,而不是通过URL参数传递。URL参数只应用于页面定位,而不是数据存储。
4. 使用TypeScript提升开发体验:为路由和参数定义接口,获得类型提示和编译时检查:
```typescript
interface RouteParams {
id: string
tab?: string
}
export default {
mounted() {
const params: RouteParams = this.$route.params
// 获得类型提示
console.log(params.id)
}
}
```
5. 定期清理路由代码:随着项目迭代,会有很多废弃路由和组件。定期检查并移除不再使用的路由配置,可以减小包体积,提高维护效率。
Vue Router作为Vue生态的核心部分,其设计思想非常符合Vue的渐进式理念。从简单的页面切换到复杂的权限控制,它都能胜任。掌握好路由管理,能让你的单页应用开发事半功倍。
话说回来,路由系统就像
最新发布
- 2023最新VueRouter3.x完全指南:从入门到精通的路由管理手册
- 2017年iOS11.1Beta升级指南:两种方法教你轻松刷入开发者预览版
- 2025年实测:苹果18W快充总断充?4个亲测有效的解决办法
- 2025年手机定位自查指南:3招教你快速判断是否被追踪(附华为Mate30实操)
- 2025年网站内部优化核心要素与实操指南——附10个关键数据指标
- 2012年索尼旗舰LT26i:静音闹钟总不响?手把手教你搞定+三年真实使用体验
- 2025年亲测有效:手机镜头进灰别乱擦,9步拆解+防灰妙招(新手也能会)
- 2025年华为畅享20Pro(EMUI10.1)截屏实测:3种方法让新手秒上手
- 2007年经典滑盖回望:三星J608的市场余温与真实用户体验
- 2014年魅族MX4Pro:2K屏+前置按压指纹的真实使用感受
相关文章
- 2023最新VueRouter3.x完全指南:从入门到精通的路由管理手册
- 2025超详细OpenWrt软路由安装指南:用VMware打造你的专属家庭网络中枢
- 2025小白必看:ICMP协议实战指南——从原理到LWIP移植全攻略
- 2023超全WiFi5(802.11ac)速率计算指南:从理论到实战的500M家庭组网全攻略
- 2023交换机配置入门:从连接到精通的5大核心实验+避坑指南
- 2025年最新!UDP丢包率从30%降到0.1%的实战指南:从小白到专家的优化之路
- 2023保姆级WireGuard组网教程:从公网穿透到内网服务器无缝访问(附10个避坑技
- 2025年最新!小白必看的AR路由器内网穿透完全指南:从配置到排障的100%实操手册
- 2025年Docker网段冲突终极解决方案:从入门到精通的避坑指南
- 2023超详细VLAN零基础入门指南:从原理到实战(附6000字避坑手册)