
前言
在 Vue 项目开发中,路由管理是构建单页应用(SPA)的核心技术之一。Vue Router 作为 Vue 官方配套的路由解决方案,不仅能实现页面间的无缝切换,还能灵活处理路由参数、导航守卫等复杂场景。
本文针对 Vue 2/3 开发者,从路由基础配置→路由导航实战→路由参数传递三大核心模块,结合真实项目场景拆解 Vue Router 的使用逻辑。内容兼顾入门易懂性与实战深度,不仅包含完整代码示例,还嵌入了原理图解和避坑技巧,无论是刚接触 Vue 的新手,还是需要夯实基础的开发者,都能从中收获干货。建议收藏本文,遇到路由问题时直接对照实操!
1. 路由基础:从安装到路由实例搭建
路由基础是后续所有操作的核心,这部分不仅要会做,还要懂为什么这么做。很多开发者踩坑,本质是对路由实例的配置逻辑理解不透彻。
1.1 安装与环境适配(Vue 2/3 区别)
Vue Router 对 Vue 2 和 Vue 3 有明确的版本区分,安装时必须对应,否则会出现兼容性报错:
Vue 2 项目:安装 Vue Router 3.x 版本(最新稳定版 3.6.5)
bashnpm install vue-router@3 --save # 或 yarn add vue-router@3Vue 3 项目:安装 Vue Router 4.x 版本(最新稳定版 4.2.5)
bashnpm install vue-router --save # 或 yarn add vue-router
避坑提示:Vue 3 无法兼容 Vue Router 3.x,反之亦然。如果安装后出现export 'default' (imported as 'VueRouter') was not found报错,先检查版本是否匹配。
1.2 路由实例核心配置详解
路由实例是路由系统的大脑,所有路由规则、全局配置都通过它定义。下面以 Vue 3 为例,拆解完整的路由实例创建流程(Vue 2 用法类似,差异会标注):
步骤 1:创建路由模块(src/router/index.js)
javascript
// Vue 3 写法
import { createRouter, createWebHistory } from 'vue-router'
// 导入需要的组件
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import NotFound from '../views/NotFound.vue'
// 1. 定义路由规则(后续详解)
const routes = [
{ path: '/', component: Home }, // 首页
{ path: '/about', component: About }, // 关于页
{ path: '/:pathMatch(.*)*', component: NotFound } // 404 页面
]
// 2. 创建路由实例
const router = createRouter({
// 路由模式:createWebHistory(HTML5 模式,无 #)/ createWebHashHistory(哈希模式,带 #)
history: createWebHistory(import.meta.env.BASE_URL), // Vue 3 环境变量获取
// history: createWebHashHistory(), // 兼容低版本浏览器
routes, // 传入路由规则(等同于 routes: routes)
// 可选配置:统一激活状态样式
linkActiveClass: 'router-active' // 替代默认的 router-link-active
})
export default router
步骤 2:在 main.js 中挂载路由
javascript
// Vue 3 写法
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 导入路由实例
const app = createApp(App)
app.use(router) // 挂载路由(关键步骤)
app.mount('#app')
Vue 2 差异点:
- 导入方式:
import Vue from 'vue'+import VueRouter from 'vue-router'- 路由实例创建:
const router = new VueRouter({ routes, mode: 'history' })- 挂载方式:
new Vue({ router, render: h => h(App) }).$mount('#app')
路由实例核心配置项图解

1.3 路由映射规则:path、component 与重定向
路由规则是路径→组件的映射关系,核心字段包括 path、component、redirect 等,下面拆解常用配置:
1.3.1 基础映射规则
javascript
const routes = [
// 1. 基础路径:path 对应 URL 路径,component 对应渲染组件
{ path: '/home', component: () => import('../views/Home.vue') }, // 懒加载写法(推荐)
// 2. 重定向:访问 / 时跳转到 /home
{ path: '/', redirect: '/home' },
// 3. 别名:访问 /index 等同于访问 /home(URL 不变)
{ path: '/home', component: Home, alias: '/index' },
// 4. 404 页面:匹配所有未定义的路径(必须放在最后)
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound }
]
关键知识点:组件懒加载
上面代码中 component: () => import('../views/Home.vue') 是组件懒加载写法,优势如下:
- 减少首屏加载时间:只有访问该路由时才会加载组件代码
- 优化代码分割:打包时会将不同组件拆分为独立的 JS 文件
- 对比直接导入:
import Home from '../views/Home.vue'会在首屏一次性加载所有组件,适合小型项目
实战建议:中大型项目优先使用懒加载,小型项目可直接导入提升开发效率。
2. 路由导航:声明式 vs 编程式导航全解析
路由导航是页面跳转的实现方式,Vue Router 提供两种核心方案:声明式导航(标签式)和编程式导航(JS 代码式),下面详细拆解用法、差异与场景。
2.1 声明式导航:<router-link> 用法与进阶
声明式导航通过 <router-link> 标签实现,无需写 JS 代码,适合静态跳转场景(如导航栏、菜单)。
2.1.1 基础用法
html
<!-- App.vue 中使用 -->
<template>
<div class="nav">
<!-- 基础跳转:to 对应路由 path -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于我们</router-link>
<!-- 带查询参数的跳转 -->
<router-link to="/user?name=zhangsan&age=20">用户中心</router-link>
<!-- 激活状态样式:默认类名 router-link-active,可通过 linkActiveClass 自定义 -->
</div>
<!-- 路由出口:匹配的组件会渲染在这里 -->
<router-view></router-view>
</template>
<style scoped>
/* 自定义激活状态样式 */
.router-link-active {
color: #4299e1;
font-weight: bold;
border-bottom: 2px solid #4299e1;
}
.nav {
display: flex;
gap: 20px;
padding: 20px;
border-bottom: 1px solid #eee;
}
</style>
2.1.2 进阶用法:动态绑定 to
当跳转路径或参数需要动态生成时,使用 v-bind:to(简写 :to):
html
<!-- 1. 绑定动态路径 -->
<router-link :to="'/user/' + userId">我的主页</router-link>
<!-- 2. 绑定对象格式(推荐,支持更多配置) -->
<router-link :to="{
path: '/user', // 路由路径
query: { name: 'zhangsan' }, // 查询参数(URL 中显示为 ?name=zhangsan)
hash: '#info' // 锚点(URL 中显示为 #info)
}">
用户中心
</router-link>
2.1.3 核心属性
| 属性名 | 作用 | 示例 |
|---|---|---|
to |
目标路由路径或对象 | to="/home" 或 :to="{ path: '/home' }" |
replace |
跳转时替换历史记录(无法回退) | <router-link to="/home" replace> |
target |
新窗口打开(类似 <a> 标签的 target="_blank") |
<router-link to="/home" target="_blank"> |
active-class |
单个路由的激活类名(优先级高于全局 linkActiveClass) | <router-link to="/home" active-class="active"> |
2.2 编程式导航:$router.push/replace 实战
编程式导航通过 this.$router(Vue 2)或 useRouter(Vue 3)提供的方法实现,适合动态跳转场景(如表单提交后跳转、按钮点击跳转)。
2.2.1 基础用法(Vue 2/3 对比)
Vue 2 写法(选项式 API)
html
<template>
<button @click="goToHome">返回首页</button>
<button @click="goToUser">跳转到用户中心</button>
</template>
<script>
export default {
methods: {
goToHome() {
// 1. 跳转到指定路径
this.$router.push('/home')
},
goToUser() {
// 2. 带参数的跳转(对象格式)
this.$router.push({
path: '/user',
query: { name: 'zhangsan' } // 查询参数
})
},
goToDetail() {
// 3. 替换历史记录(无法回退)
this.$router.replace('/user/detail')
},
goBack() {
// 4. 回退上一页(类似浏览器后退按钮)
this.$router.go(-1) // -1 表示上一页,1 表示下一页
}
}
}
</script>
Vue 3 写法(组合式 API)
html
<template>
<button @click="goToHome">返回首页</button>
<button @click="goToUser">跳转到用户中心</button>
</template>
<script setup>
// 导入 useRouter 钩子
import { useRouter } from 'vue-router'
const router = useRouter() // 替代 Vue 2 中的 this.$router
const goToHome = () => {
router.push('/home')
}
const goToUser = () => {
router.push({
path: '/user',
query: { name: 'zhangsan' }
})
}
const goToDetail = () => {
router.replace('/user/detail')
}
const goBack = () => {
router.go(-1)
}
</script>
2.2.2 编程式导航避坑点
-
重复点击相同路由报错:当多次点击同一个编程式导航按钮时(如连续点击返回首页),会出现Uncaught (in promise) NavigationDuplicated报错。解决方案:在路由实例中添加全局守卫处理:
javascript// src/router/index.js const router = createRouter({ ... }) // 解决重复点击路由报错问题 const originalPush = router.push router.push = function push(location) { return originalPush.call(this, location).catch(err => err) } -
$router与$route区别:$router:路由实例对象,包含push、replace等导航方法(全局唯一)$route:当前路由对象,包含path、query、params等路由信息(每个路由独有) 实战提示:导航用$router,获取当前路由信息用$route。
2.3 两种导航的适用场景与对比

实战总结:
- 静态跳转(如导航栏)用声明式导航,高效简洁;
- 动态跳转(如表单提交后、带条件判断)用编程式导航,灵活可控。
3. 路由参数传递:灵活传参与组件解耦
路由参数传递是页面间数据通信的核心方式,Vue Router 提供三种常用方案:动态路由匹配、查询参数、路由 props 解耦。下面拆解每种方案的用法、场景与优缺点。
3.1 动态路由匹配:/user/:id 用法与原理
动态路由匹配通过在 path 中添加动态参数(如 :id)实现,适合传递必填参数(如用户 ID、商品 ID),参数会显示在 URL 路径中(如 /user/123)。
3.1.1 基础配置与使用
步骤 1:配置动态路由规则
javascript
// src/router/index.js
const routes = [
// 动态路由::id 是动态参数,可自定义名称(如 :userId)
{ path: '/user/:id', name: 'User', component: () => import('../views/User.vue') }
]
步骤 2:跳转传递参数
html
<!-- 1. 声明式导航传递 -->
<router-link :to="'/user/' + 123">用户 123 的主页</router-link>
<!-- 或对象格式(推荐,更清晰) -->
<router-link :to="{ path: '/user/123' }">用户 123 的主页</router-link>
<router-link :to="{ name: 'User', params: { id: 123 } }">用户 123 的主页</router-link>
<!-- 2. 编程式导航传递 -->
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const goToUser = (userId) => {
// 方式 1:直接拼接路径
router.push(`/user/${userId}`)
// 方式 2:对象格式(path + params 不生效,需用 name + params)
router.push({
name: 'User', // 必须用 name 匹配路由,不能用 path
params: { id: userId }
})
}
</script>
步骤 3:组件中接收参数
html
<!-- User.vue 中接收参数 -->
<template>
<div>用户 ID:{{ $route.params.id }}</div>
</template>
<!-- Vue 3 组合式 API 写法 -->
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute() // 获取当前路由对象
console.log('用户 ID:', route.params.id) // 输出 123
</script>
3.1.2 动态路由的高级用法
(1)多参数匹配
javascript
// 路由规则
{ path: '/user/:id/:name', name: 'User', component: User }
// 跳转
router.push({ name: 'User', params: { id: 123, name: 'zhangsan' } })
// URL 结果:/user/123/zhangsan
// 接收
console.log(route.params.id) // 123
console.log(route.params.name) // zhangsan
(2)可选参数(Vue Router 4+ 支持)
在参数后加 ? 表示该参数可选:
javascript
// 路由规则:id 可选
{ path: '/user/:id?', name: 'User', component: User }
// 支持两种 URL:/user 和 /user/123
避坑提示:Vue Router 3 不支持可选参数,需通过重定向实现:
javascript// Vue 2 兼容方案 { path: '/user', redirect: '/user/default' }, { path: '/user/:id', component: User }
3.2 查询参数:?name=xxx 传参技巧
查询参数通过 ? 拼接在 URL 后(如 /user?name=zhangsan&age=20),适合传递非必填参数(如筛选条件、分页参数),参数可多个拼接,且刷新页面后参数不会丢失。
3.2.1 基础用法
步骤 1:跳转传递参数
html
<!-- 1. 声明式导航 -->
<router-link to="/user?name=zhangsan&age=20">用户中心</router-link>
<!-- 对象格式 -->
<router-link :to="{
path: '/user',
query: { name: 'zhangsan', age: 20 }
}">用户中心</router-link>
<!-- 2. 编程式导航 -->
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const goToUser = () => {
router.push({
path: '/user',
query: { name: 'zhangsan', age: 20 }
})
}
</script>
步骤 2:组件中接收参数
html
<template>
<div>用户名:{{ $route.query.name }}</div>
<div>年龄:{{ $route.query.age }}</div>
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log('用户名:', route.query.name) // zhangsan
console.log('年龄:', route.query.age) // 20(注意:query 参数默认是字符串类型)
</script>
3.2.2 核心特点
- URL 可见:参数显示在 URL 中,适合需要分享链接的场景
- 刷新不丢失:页面刷新后 query 参数依然存在(动态路由的 params 也不丢失)
- 类型限制:所有参数默认是字符串类型,需手动转换(如
Number(route.query.age)) - 可选性:可传递任意数量的参数,无需在路由规则中预先定义
3.3 路由 props 解耦:告别 $route.params
上面两种接收参数的方式都需要用到 $route.params 或 $route.query,这种写法的问题是组件与路由强耦合------ 组件必须依赖路由对象才能获取参数,无法单独复用。
路由 props 解耦的核心作用是:将路由参数自动映射为组件的 props 属性,组件无需关心路由,只需接收 props 即可,实现组件复用。
3.3.1 三种 props 配置方式
方式 1:布尔值模式(适用于动态路由 params)
javascript
// 路由规则中设置 props: true
const routes = [
{
path: '/user/:id',
name: 'User',
component: User,
props: true // 自动将 params 中的参数映射为组件 props
}
]
// User.vue 中接收
<template>
<div>用户 ID:{{ id }}</div> <!-- 直接使用 props 中的 id -->
</template>
<script setup>
// 定义 props 接收
const props = defineProps(['id'])
console.log('用户 ID:', props.id) // 123
</script>
方式 2:对象模式(适用于固定参数)
javascript
// 路由规则中设置 props 为对象
const routes = [
{
path: '/user',
component: User,
props: { name: '默认用户', age: 18 } // 固定参数
}
]
// User.vue 中接收
const props = defineProps(['name', 'age'])
console.log(props.name) // 默认用户
console.log(props.age) // 18
方式 3:函数模式(适用于复杂场景,推荐)
函数模式可以自定义参数映射逻辑,支持 params、query 混合传递:
javascript
// 路由规则中设置 props 为函数
const routes = [
{
path: '/user/:id',
component: User,
// route 是当前路由对象
props: (route) => ({
userId: route.params.id, // 重命名参数(id → userId)
userName: route.query.name, // 结合 query 参数
age: Number(route.query.age) // 类型转换
})
}
]
// User.vue 中接收
const props = defineProps(['userId', 'userName', 'age'])
console.log(props.userId) // 123(来自 params)
console.log(props.userName) // zhangsan(来自 query)
console.log(props.age) // 20(数字类型,来自 query)
3.3.2 props 解耦的优势图解

实战建议:中大型项目优先使用 props 解耦,尤其是需要复用的组件;小型项目可直接使用
$route.params提升开发效率。
4. 实战避坑指南:常见问题与解决方案
4.1 动态路由跳转后,刷新页面参数丢失?
- 问题描述:使用
name + params跳转后,刷新页面params参数丢失。 - 原因:Vue Router 的
params参数在哈希模式(createWebHashHistory)下刷新会丢失,HTML5 模式(createWebHistory)下不会。 - 解决方案:
- 改用 HTML5 模式(需后端配置支持,避免 404);
- 重要参数改用 query 传递(刷新不丢失);
- 哈希模式下,将参数存储在 localStorage 中。
4.2 编程式导航重复点击报错?
-
问题描述:多次点击同一个编程式导航按钮,出现NavigationDuplicated报错。
-
解决方案:在路由实例中重写
push方法(前文已讲),或使用catch捕获错误:javascriptrouter.push('/home').catch(err => {})
4.3 路由 props 不生效?
- 常见原因:
- 动态路由使用 props: true 时,参数是
params而非query; - 函数模式下,路由对象参数名错误(如
route.query写成route.params); - 组件未定义对应的 props(如路由配置
userId,组件 props 写id)。
- 动态路由使用 props: true 时,参数是
4.4 404 页面不生效?
-
问题描述:访问未定义的路由时,404 页面不渲染。
-
原因:404 路由规则未放在最后,被前面的路由规则匹配。
-
解决方案:将 404 路由放在 routes 数组最后:
javascriptconst routes = [ { path: '/home', component: Home }, { path: '/about', component: About }, // 404 路由放在最后 { path: '/:pathMatch(.*)*', component: NotFound } ]
5. 总结与进阶学习方向
本文从路由基础→路由导航→路由参数三大核心模块,详细拆解了 Vue Router 的实战用法,涵盖安装配置、跳转方式、参数传递、避坑技巧等关键知识点。掌握这些内容后,足以应对中大型 Vue 项目的路由管理需求。
核心要点回顾
- 路由基础:优先使用组件懒加载优化首屏性能,404 路由放在最后;
- 路由导航:静态跳转用
<router-link>,动态跳转用$router.push; - 路由参数:必填参数用动态路由,非必填用 query,组件复用用 props 解耦;
- 避坑关键:注意 Vue 2/3 版本差异,避免重复点击报错和参数丢失。
进阶学习方向
- 嵌套路由:实现页面内多级导航(如
/user/123/profile); - 路由守卫:控制路由跳转权限(如登录验证、权限判断);
- 路由元信息:通过
meta配置路由权限、标题等(如meta: { requiresAuth: true }); - 路由懒加载进阶:结合
webpackChunkName自定义打包文件名。
如果你在使用 Vue Router 时遇到了其他问题,或者有更好的实战技巧,欢迎在评论区留言交流!如果本文对你有帮助,别忘了点赞 + 收藏 + 关注,后续会更新更多 Vue 实战干货~
结尾互动
你在 Vue 项目中使用路由时,遇到过哪些印象深刻的坑?是怎么解决的?欢迎在评论区分享你的经历,让更多开发者少走弯路!
