Vue3 路由配置和使用与讲解(超级详细)

引言:Vue 3 作为当前最受欢迎的前端框架之一,搭配其官方路由解决方案 Vue Router,为我们提供了强大、灵活且易于上手的路由管理能力。

本篇文章将带你从零开始,超级详细地讲解 Vue 3 中 Vue Router 的安装、配置与实战用法。你将学会:

如何在 Vue 3 项目中安装并初始化 vue-router;

声明路由规则,实现组件与路径的映射;

使用 router-link 和编程式导航进行页面跳转;

动态路由、嵌套路由、命名视图等高级用法;

路由守卫(导航守卫)的使用场景与最佳实践;

以及 Vue 3 组合式 API(setup)中如何正确使用路由。

无需担心基础是否扎实,我们将一步步深入,结合代码示例与图解,确保你不仅能"会用",更能"理解"。

一.安装相关的组件(必不可少的)

简单的运行(最简单)

(一)安装 Vue Router​

创建路由需要安装vue-router,可以通过 npm 进行安装。

打开终端:

在后端中输入

javascript

复制代码

npm install vue-router@4

(二)创建文件夹与文件(路径)

在src中创建router文件夹与views文件夹:分别在里面创建相应的文件

其中router文件夹中的index.ts文件用于配置路由实例

index.ts:

TypeScript

复制代码

// 把官方工具函数一次性引进来

import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'

// 把真正的页面组件引进来

import HomeView from '@/views/HomeView.vue'

import UserView from '@/views/UserView.vue'

import ListView from '@/views/ListView.vue'

// 创建"路由实例"------可以理解成"路由的大脑"

const router = createRouter({

// 3.1 决定浏览器地址栏长什么样

// createWebHistory() → /home (好看,但需要后端配合)

// createWebHashHistory() → /#/home (带 #,兼容老浏览器)

history: createWebHashHistory(),

// 3.2 真正的路由表:告诉大脑"什么地址对应什么页面"

routes: [

{ // 访问 /home 时渲染 HomeView

path: '/home',

name: 'home',

component: HomeView,

children: [ // 嵌套路由:/home/list/123

{

path: 'list/:id', // 动态段,将来 this.$route.params.id 取值

name: 'list',

component: ListView

}

]

},

{ // 访问 /user 时渲染 UserView

path: '/user',

name: 'user',

component: UserView

}

]

})

// 把"大脑"暴露出去,main.ts 里用 app.use(router) 激活

export default router

一句话先总结

index.ts 就是 "路由的大门口" :

1 告诉 Vue Router 有哪些页面 (路由表)

2 告诉浏览器 用哪种历史模式 (hash / history)

3 把 路由实例 导出给 main.ts,让整站激活路由功能

把它当"户口簿"

地址(path) = 门牌号

组件(component) = 住在房子里的人

名字(name) = 别名,方便编程导航

history / hash = 走前门还是后门

整个文件就是告诉 Vue Router:

"谁住哪栋楼、怎么走、门牌号叫什么",然后导出给应用统一使用。

(三)让Vue应用使用路由(main)

问个问题哈:为什么我在 .vue 组件里可以拿到 src/router/index.ts 中导出的 router 实例?它们明明不在同一个文件。

一般来说肯定是不行的,所以我们需要用到main.ts

在 main.ts 里已经把 router "注册" (app.use(router))到整个 Vue 应用中,Vue 会:

把 router 实例注入为全局属性

模板里:$router / $route

组合式 API:import { useRouter, useRoute } from 'vue-router'

让所有子组件共享同一份路由对象

不论你在哪个 .vue 文件,只要组件属于该应用,就能随时拿到同一份 router。

main.ts的原来的代码:

TypeScript

复制代码

import './assets/main.css'

import { createApp } from 'vue'

import App from './App.vue'

createApp(App).mount('#app')

main.ts的源代码

TypeScript

复制代码

// src/main.js

import { createApp } from 'vue'

import App from './App.vue'

import router from './router' //导入设为全局变量

createApp(App).use(router).mount('#app') //将其挂载

现在我们就可以在.vue文件中拿到了router实例

(四)在 Vue 应用中使用路由​

App.vue

TypeScript

复制代码

解释一下哈:

TypeScript

复制代码

import {RouterView,RouterLink} from 'vue-router'

首页

个人中心

这三行代码就是 Vue Router 的"骨架",作用一句话概括:

负责"跳", 负责"显示页面"。

1.我们先导入

TypeScript

复制代码

import { RouterView, RouterLink } from 'vue-router'

把官方提供的两个核心组件引进来:

RouterLink:可点击的超链接,但会拦截浏览器默认跳转,改由 Vue Router 处理。

RouterView>:占位符,真正渲染匹配到的页面组件。

2.声明式导航

TypeScript

复制代码

首页

个人中心

to="/home":告诉路由器"点我时去 /home"。

active-class="active":当 URL 等于 /home 时,自动给这个 加 class="active",方便写高亮样式。

3.页面出口

TypeScript

复制代码

路由匹配成功后,把对应组件渲染到这里。

嵌套路由时,父级 渲染父级组件,子级 渲染子级组件。

如果还不懂:一句话记忆

RouterLink 像 ,用来"点";

RouterView 像"电视屏幕",用来"播"。

这个时候恭喜你成功创建了一个路由并且可以成功使用

先点击运行项目进入网址:

接下来我们进行代码的详解与拓展

在这之前我们先来点小问题测试一下

为什么我在 .vue 组件里可以拿到 router 实例?

这是因为我们在 main.ts 中通过 app.use(router) 将路由注册到了全局。Vue 会自动将 router 实例挂载到所有组件上,因此你可以在任何地方通过 this.$router 或者组合式 API 的 useRouter() 来访问它。

什么是嵌套路由?

嵌套路由允许你在已有路由的基础上进一步细分。比如 /home/list/123,其中 /home 是父路由,list/123 是子路由。

createWebHistory vs createWebHashHistory?

createWebHistory():生成干净的 URL(如 /home),但需要后端服务器支持。

createWebHashHistory():生成带 # 的 URL(如 /#/home),兼容性更好,不需要后端支持。

选择哪种方式取决于你的项目需求。

如何传递参数给路由?

有两种方式:

路径参数 :通过 path: 'list/:id' 定义,然后在目标组件中通过 this.$route.params.id 获取。

查询参数 :通过 ?key=value 形式传递,例如 /home?name=John,在组件中通过 this.$route.query.name 获取。

二.路由配置详解

Vue Router 4 支持两种主要的路由模式:Hash 模式和 History 模式。​

一、Hash 模式(默认模式)

什么是 Hash?

你可能见过这样的网址:

XML

复制代码

https://example.com/#/home

https://example.com/#/about

注意那个 # 符号,它后面的部分叫做 hash (哈希值)。浏览器有一个特性:改变 hash 值不会导致页面刷新,而且浏览器会记录这个变化,支持前进后退。

当你点击一个路由链接(比如 ),Vue Router 会把地址栏变成:

XML

复制代码

https://example.com/#/about

它只是修改了 URL 中 # 后面的部分。

因为只改了 hash,浏览器不会向服务器发送请求,页面不刷新。

Vue Router 监听 hash 的变化,一旦变了,就去加载对应的组件并显示。

配置方式如下:

TypeScript

复制代码

const router = createRouter({

history: createWebHashHistory(),

routes: [...]

})

优点:

兼容性好:支持所有浏览器,包括很老的 IE。

部署简单 :不需要服务器配置。因为 # 后面的内容不会发给服务器,所以无论你访问 /#/home 还是 /#/about,服务器收到的请求都是 /,返回 index.html 即可。

缺点:

URL 不够美观 :带 #,看起来有点"丑"。

不符合现代 Web 趋势:现在的网站都追求"干净"的 URL。

二、History 模式

什么是 History API?

现代浏览器提供了一套叫 History API 的接口(比如 pushState、replaceState),允许我们在不刷新页面的情况下,修改浏览器地址栏的 URL,并添加到历史记录中。

Vue Router 的 History 模式怎么工作?

当你点击 ,地址栏会变成:

复制代码

https://example.com/about

看起来就像一个正常的页面路径,没有 #。

浏览器不会刷新,Vue Router 捕获这个变化,动态加载对应的组件。

配置方法如下:

TypeScript

复制代码

// 使用 History 模式

const router = createRouter({

history: createWebHistory(),

routes: [...]

})

优点:

URL 干净美观 :没有 #,像传统网站一样。

用户体验更好:更符合用户对 URL 的认知。

缺点:

⚠️ 这是关键!很多人用 History 模式时出问题,就是因为忽略了这一点。

问题:刷新页面 404!

当你在浏览器里访问 https://example.com/about,浏览器会向服务器请求 /about 这个路径。

但你的项目是单页应用,所有路由都由前端控制 ,服务器上根本没有 /about 这个文件或路径。

所以服务器返回 404 错误 ❌。

三、对比总结

特性

Hash 模式

History 模式

URL 示例

/#/about

/about

是否需要服务器配置

❌ 不需要

✅ 必须配置,否则刷新 404

兼容性

✅ 极好,支持老浏览器

✅ 现代浏览器都支持(IE10+)

URL 美观度

❌ 有 #,不够美观

✅ 干净、专业

使用难度

✅ 简单,开箱即用

⚠️ 需要服务器配合

动态路由

什么是动态路由?想象你有一个用户管理系统,每个用户的页面 URL 都不一样:

javascript

复制代码

/user/1

/user/2

/user/100

你不可能为每个用户都写一个路由,比如:

javascript

复制代码

{ path: '/user/1', component: User }

{ path: '/user/2', component: User }

...

{ path: '/user/100', component: User }

这样写代码就太慢了,耗费时间,维护起来也崩溃。

动态路由就是:用一个路由规则,匹配一类结构相似的 URL。

javascript

复制代码

/user/:id → 匹配 /user/1、/user/2、/user/abc

这里的 :id 是一个动态片段,它会捕获 URL 中对应的部分,传给组件使用。

动态路由怎么写?(语法)

在 Vue Router 中,使用冒号 : 来定义动态段。

javascript

复制代码

const routes = [

{

path: '/user/:id',

component: User

},

{

path: '/post/:year/:month/:day',

component: BlogPost

}

]

/user/123 → 匹配,id = '123'

/user/tom → 匹配,id = 'tom'

/post/2025/04/01 → 匹配,year='2025', month='04', day='01'

注意:动态参数是字符串类型,即使看起来像数字(如 123),也是字符串 '123'。

在组件中如何获取动态参数?

有 两种主要方式 获取 :id、:year 这些动态值。

方法 1:通过 this.$route.params(选项式 API)

javascript

复制代码

方法 2:使用 useRoute()(组合式 API,推荐)

javascript

复制代码

动态路由的匹配规则

1. 可选参数 (用 ?)

javascript

复制代码

{ path: '/user/:id?' } // :id 可有可无

匹配:/user 和 /user/123

2. 零或多个 (*)和 一或多个 (+)

javascript

复制代码

{ path: '/user/:id*' } // :id 可以出现 0 次或多次(很少用)

{ path: '/user/:id+' } // :id 至少出现 1 次

注意:* 和 + 是针对"路径段"的重复,不是字符重复。

拓展:

嵌套路由 + 动态路由

假设你有用户详情页,还有子页面:资料、订单、设置。

javascript

复制代码

/user/1/profile

/user/1/orders

/user/1/settings

可以这样写:

javascript

复制代码

{

path: '/user/:id',

component: UserLayout,

children: [

{ path: 'profile', component: Profile },

{ path: 'orders', component: Orders },

{ path: 'settings', component: Settings }

]

}

在 UserLayout 组件中,可以通过 this.$route.params.id 拿到 id。

动态路由 + 路由守卫:权限控制

动态路由常配合 路由守卫 使用,比如:

根据 id 判断用户是否合法

是否有权限查看该页面

javascript

复制代码

router.beforeEach((to, from, next) => {

const userId = to.params.id

if (userId === 'admin') {

alert('禁止访问!')

next('/error')

} else {

next()

}

})

实际开发建议

命名规范

动态参数命名要有意义,比如:

:userId 而不是 :id

:postId 而不是 :p

javascript

复制代码

{ path: '/:pathMatch(.*)*', component: NotFound }

提高代码可读性。

类型转换

动态参数是字符串,如果需要数字,记得转换:

javascript

复制代码

const id = parseInt(route.params.id)

处理 404(未匹配路由)

一定要加一个"兜底"路由,防止用户访问不存在的路径:

这个路由会匹配所有没有被前面规则匹配到的路径,通常用于显示 404 页面。

注意:这个路由要放在所有路由的最后!

动态路由的典型应用场景

场景

示例 URL

动态参数

用户详情

/user/123

:id

文章详情

/post/456

:postId

商品页面

/product/789

:productId

博客归档

/blog/2025/04

:year, :month

GitHub 仓库页面

/repo/vuejs/core

:owner, :repo

总结一句话:

动态路由就是用 :param 的方式,让一个路由规则匹配多个相似的 URL,并在组件中通过 $route.params 获取动态部分的值,实现灵活、可复用的页面跳转。

小练习(巩固理解)

试着写出以下场景的路由:

显示某个城市的天气:/weather/beijing

查看某本书的第几章:/book/1/chapter/5

用户个人主页,用户名可选:/profile 或 /profile/john

javascript

复制代码

[

{ path: '/weather/:city', component: Weather },

{ path: '/book/:bookId/chapter/:chapterNum', component: Chapter },

{ path: '/profile/:username?', component: Profile }

]

编程式导航(Programmatic Navigation)

什么是编程式导航?

在 Vue 项目中,我们通常有两种方式让页面"跳转":

声明式导航 :用 标签,点击就跳转。

编程式导航:用 JavaScript 代码来控制跳转。

编程式导航 = 用 JS 代码实现页面跳转、前进、后退等操作。

它就像你"手动驾驶"导航,而不是让乘客(用户)自己点

为什么要用编程式导航?

因为不是所有跳转都能靠 完成。比如:

用户登录成功后,自动跳转到首页 ✅

表单提交后,跳转到成功页 ✅

点击按钮前要先验证权限,再决定是否跳转 ✅

点击"上一页"按钮,返回上一个页面 ✅

这些都需要 在 JS 中写逻辑判断 + 手动跳转,这就是编程式导航的用武之地。

核心方法:router.push() 和 router.go()

Vue Router 提供了几个关键的 API:

1. router.push() ------ 跳转到新页面(类似点击链接)

这是最常用的编程式导航方法。

javascript

复制代码

import { useRouter } from 'vue-router'

const router = useRouter()

// 跳转到 /home

router.push('/home')

// 也可以传对象

router.push({ path: '/home' })

// 命名路由跳转(推荐)

router.push({ name: 'User', params: { id: 123 } })

// 对应路由:{ name: 'User', path: '/user/:id' }

// 带查询参数:/search?q=vue

router.push({ path: '/search', query: { q: 'vue' } })

push 的意思是"把新页面压入历史栈",所以浏览器可以点击"后退"回到上一页。

等待跳转完成(Promise)

router.push() 返回一个 Promise,可以知道跳转是否成功:

javascript

复制代码

router.push('/home').then(() => {

console.log('跳转成功!')

}).catch(err => {

console.log('跳转失败:', err)

})

跳转失败通常是:守卫阻止了跳转(比如没登录)。

2. router.replace() ------ 替换当前页面

和 push 类似,但不会在历史记录中留下记录。

javascript

复制代码

router.replace('/login')

// 或

router.replace({ name: 'Login' })

效果:跳转后,用户点"后退"按钮,不会回到原来的页面(因为被替换了)。

应用场景:

登录页替换首页(防止登录后点后退还回到首页)

错误页面替换当前页

3. router.go(n) ------ 控制浏览器前进后退

相当于调用 window.history.go(n)。

javascript

复制代码

router.go(-1) // 后退一页(等同于点击浏览器后退)

router.go(1) // 前进一页

router.go(2) // 前进两页

router.go(-2) // 后退两页

如果历史记录不够,会静默失败。

4. 其他方法(了解即可)

方法

说明

router.back()

等价于 router.go(-1)

router.forward()

等价于 router.go(1)

在哪里使用编程式导航?

组合式 API(

$router 是全局路由实例,$route 是当前路由信息。

注意事项和常见问题

1. 避免重复导航到当前路由

javascript

复制代码

router.push('/home') // 如果已经在 /home,会报错

Vue Router 会抛出一个 NavigationDuplicated 类型的错误。

✅ 解决方案:捕获错误或判断是否已经是当前页。

javascript

复制代码

router.push('/home').catch(err => {

if (err.name !== 'NavigationFailure') {

console.log(err)

}

})

2. push vs replace

push:添加历史记录 ✅(用户可后退)

replace:替换当前记录 🔁(用户无法后退)

根据业务选择。

3. 动态路由参数更新,组件不刷新?

比如从 /user/1 跳到 /user/2,User 组件不会重新创建。

✅ 解决方案:

监听 $route 变化(选项式)

或使用 watch(route, ...)(组合式)

javascript

复制代码

import { useRoute } from 'vue-router'

import { watch } from 'vue'

const route = useRoute()

watch(() => route.params.id, (newId) => {

// id 变了,重新加载用户数据

})

编程式导航就是用 JavaScript 代码(如 router.push()、router.go())来控制页面跳转、前进、后退,适用于需要逻辑判断、自动跳转等复杂场景,是 的强大补充。

路由守卫(Navigation Guards)

什么是路由守卫?

想象你正在做一个后台管理系统,有些页面(比如 /admin)只能管理员访问。普通用户如果试图访问,应该被拦截并跳转到登录页。

路由守卫就是:在"页面跳转"的过程中,设置一些"检查点",决定是否允许跳转、重定向、或者做些其他操作。

它就像一个"门卫",在你进入某个页面前,问你:"你有权限吗?登录了吗?能进吗?"

路由守卫的分类

Vue Router 提供了多种守卫,按作用范围分为三类:

全局守卫(Global)------ 所有路由跳转都会经过

路由独享守卫(Per-Route)------ 只对某个特定路由生效

组件内守卫(In-Component)------ 写在组件内部,控制该组件的进入/离开

我们一个一个来讲解。

一、全局守卫(Global Guards)

1. beforeEach ------ 全局前置守卫(最常用)

在每次路由跳转前执行,可以决定是否放行。

基本语法:

javascript

复制代码

router.beforeEach((to, from, next) => {

// to: 即将进入的路由

// from: 当前离开的路由

// next: 必须调用,决定如何导航

})

示例:登录权限控制

javascript

复制代码

router.beforeEach((to, from, next) => {

const isLogged = localStorage.getItem('token')

// 如果要去的是 /admin,但没登录

if (to.path === '/admin' && !isLogged) {

next('/login') // 跳转到登录页

} else {

next() // 放行

}

})

next() 的用法:

写法

作用

next()

放行,进入目标页面

next(false)

中断跳转,停留在当前页

next('/login')

跳转到指定页面(重定向)

next({ name: 'Home' })

跳转到命名路由

next(new Error('拒绝访问'))

抛出错误,会被 onError 捕获

必须调用 next(),否则页面会卡住!

beforeResolve ------ 全局解析守卫

和 beforeEach 类似,但在所有组件内守卫和异步组件加载完毕后才触发。

适用于:需要等所有准备工作完成后再确认跳转。

javascript

复制代码

router.beforeResolve((to, from, next) => {

// 例如:检查页面权限、预加载数据等

next()

})

afterEach ------ 全局后置钩子(不用 next)

在路由跳转完成后执行,不能阻止跳转,常用于:

页面埋点(统计 PV)

修改页面标题

关闭 loading 动画

javascript

复制代码

router.afterEach((to, from) => {

document.title = to.meta.title || '默认标题'

console.log('页面已跳转')

})

它没有 next(),只是"事后通知"。

三、组件内守卫(In-Component Guards)

写在组件内部,用于控制该组件的进入、离开或更新。

1. beforeRouteEnter ------ 进入组件前

javascript

复制代码

export default {

beforeRouteEnter(to, from, next) {

// 注意:此时组件实例还未创建,不能访问 `this`

next(vm => {

// 在 `next` 的回调中可以访问组件实例 `vm`

console.log(vm) // 组件实例

})

}

}

常用于:进入前获取数据。

2. beforeRouteUpdate ------ 组件被复用时(如动态路由 /user/1 → /user/2)

javascript

复制代码

beforeRouteUpdate(to, from, next) {

// 组件实例已存在,可以访问 `this`

this.fetchUserData(to.params.id) // 重新加载用户数据

next()

}

3. beforeRouteLeave ------ 离开组件前

javascript

复制代码

beforeRouteLeave(to, from, next) {

const answer = window.confirm('你确定要离开吗?未保存的数据会丢失!')

if (answer) {

next()

} else {

next(false)

}

}

常用于:防止用户误操作离开(如表单未保存)。

实际应用场景

场景

使用守卫

用户登录验证

beforeEach

页面访问权限(如 VIP)

beforeEnter 或 beforeEach

表单未保存提醒

beforeRouteLeave

页面标题设置

afterEach

数据预加载

beforeRouteEnter

路由参数变化时更新数据

beforeRouteUpdate

注意事项

1. 必须调用 next()

否则跳转会挂起,页面卡住。

2. 避免无限重定向

javascript

复制代码

router.beforeEach((to, from, next) => {

next('/login') // ❌ 错误:每次都重定向,死循环

})

正确写法:

javascript

复制代码

if (to.path !== '/login') {

next('/login')

} else {

next()

}

3. beforeRouteEnter 不能访问 this

因为组件还没创建。需要用 next(vm => { ... }) 回调。

4. 组合式 API 中如何使用?

Vue 3 推荐使用 setup() 或

组合式 API(推荐):

javascript

复制代码

3. 在布局组件中使用

比如你想根据 meta.layout 决定使用哪个布局:

javascript

复制代码

{

path: '/admin',

component: Admin,

meta: { layout: 'AdminLayout' }

}

在根组件中:

javascript

复制代码

4. 配合 使用

会自动暴露 route 和 Component,你可以结合 meta 做动画或缓存判断:

javascript

复制代码

实际应用场景

场景

使用方式

权限控制

meta: { requiresAuth: true, roles: ['admin'] }

页面标题

meta: { title: '用户中心' }

SEO 信息

meta: { metaTitle: '...', description: '...' }

缓存控制

meta: { keepAlive: true }

动画效果

meta: { transition: 'fade' }

面包屑导航

meta: { breadcrumb: '用户管理' }

页面埋点

meta: { track: true }

注意事项

1. meta 是只读的

不要在运行时修改 route.meta,它是只读的。

2. 深度合并

如果你使用嵌套路由,meta 字段不会自动合并。你需要手动处理。

javascript

复制代码

{

path: '/user',

meta: { requiresAuth: true },

children: [

{ path: 'profile', component: Profile } // 不会继承 requiresAuth

]

}

解决方案:在守卫中递归检查所有匹配的路由:

Kotlin

复制代码

router.beforeEach((to, from, next) => {

const requiresAuth = to.matched.some(record => record.meta.requiresAuth)

if (requiresAuth && !isLogged) {

next('/login')

} else {

next()

}

})

to.matched 是一个数组,包含所有匹配的路由记录(包括父路由),非常适合做权限聚合。

3. 类型提示(TypeScript)

如果你用 TypeScript,可以为 meta 提供类型:

javascript

复制代码

import 'vue-router'

declare module 'vue-router' {

interface RouteMeta {

title?: string

requiresAuth?: boolean

roles?: string[]

keepAlive?: boolean

[key: string]: any // 允许其他自定义字段

}

}

这样在 route.meta.xxx 时就有智能提示了。

总结一句话:

路由元信息(meta)是一个"自定义数据容器",你可以在路由配置中添加任意信息(如权限、标题、缓存等),然后在守卫、组件、布局中读取它,实现灵活的页面控制和逻辑判断。

路由,看似只是"页面跳转",实则是整个应用的骨架与脉络。一个好的路由设计,能让代码更清晰、权限更安全、用户体验更流畅。

希望这篇博客能帮你真正掌握 Vue Router 的核心能力,不再只是"会用",而是"懂它"。

现在,是时候打开你的项目,用这些知识去打造一个更智能、更健壮的前端应用了!

路由不止是路径,更是用户体验的起点。

英雄联盟手游卡在加载界面进不去?快来学习解决方法
兰博基尼是哪个公司旗下的?