引言: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
<script setup lang="ts">
import {RouterView,RouterLink} from 'vue-router'
</script>
<template>
<div class="app">
<h2>路由测试</h2>
<!-- 导航-->
<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterLink to="/user" active-class="active">个人中心</RouterLink>
<!-- 路由页面展示-->
<router-view></router-view>
</div>
</template>
<style scoped>
</style>
解释一下哈:
TypeScript
import {RouterView,RouterLink} from 'vue-router'
<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterLink to="/user" active-class="active">个人中心</RouterLink>
<router-view></router-view>
这三行代码就是 Vue Router 的"骨架",作用一句话概括:
<RouterLink>负责"跳",<RouterView>负责"显示页面"。
1.我们先导入
TypeScript
import { RouterView, RouterLink } from 'vue-router'
把官方提供的两个核心组件引进来:
RouterLink:可点击的超链接,但会拦截浏览器默认跳转,改由 Vue Router 处理。
RouterView>:占位符,真正渲染匹配到的页面组件。
2.声明式导航
TypeScript
<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterLink to="/user" active-class="active">个人中心</RouterLink>
to="/home":告诉路由器"点我时去/home"。
active-class="active":当 URL 等于/home时,自动给这个<a>加class="active",方便写高亮样式。
3.页面出口
TypeScript
<router-view></router-view>
路由匹配成功后,把对应组件渲染到这里。
嵌套路由时,父级
<router-view>渲染父级组件,子级<router-view>渲染子级组件。
如果还不懂:一句话记忆
RouterLink像<a>,用来"点";
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 值不会导致页面刷新,而且浏览器会记录这个变化,支持前进后退。
当你点击一个路由链接(比如 <router-link to="/about">),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 模式怎么工作?
-
当你点击
<router-link to="/about">,地址栏会变成: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
<template>
<div>
<h2>用户 ID:{{ $route.params.id }}</h2>
</div>
</template>
<script>
export default {
created() {
console.log(this.$route.params.id) // 比如 '123'
}
}
</script>
方法 2:使用 useRoute()(组合式 API,推荐)
javascript
<template>
<div>
<h2>用户 ID:{{ id }}</h2>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
const id = route.params.id
</script>
动态路由的匹配规则
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而不是:pjavascript{ 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 项目中,我们通常有两种方式让页面"跳转":
- 声明式导航 :用
<router-link to="/home">标签,点击就跳转。 - 编程式导航:用 JavaScript 代码来控制跳转。
编程式导航 = 用 JS 代码实现页面跳转、前进、后退等操作。
它就像你"手动驾驶"导航,而不是让乘客(用户)自己点 <router-link>。
为什么要用编程式导航?
因为不是所有跳转都能靠 <router-link> 完成。比如:
- 用户登录成功后,自动跳转到首页 ✅
- 表单提交后,跳转到成功页 ✅
- 点击按钮前要先验证权限,再决定是否跳转 ✅
- 点击"上一页"按钮,返回上一个页面 ✅
这些都需要 在 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(<script setup>)------推荐
javascript
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
function goToHome() {
router.push('/home')
}
function goToUser(id) {
router.push({ name: 'User', params: { id } })
}
function goBack() {
router.go(-1)
}
</script>
<template>
<button @click="goToHome">去首页</button>
<button @click="goToUser(123)">去用户页</button>
<button @click="goBack">后退</button>
</template>
$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())来控制页面跳转、前进、后退,适用于需要逻辑判断、自动跳转等复杂场景,是<router-link>的强大补充。
路由守卫(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() 或 <script setup>,可以用以下方式:
javascript
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
onBeforeRouteLeave((to, from, next) => {
const answer = confirm('确定离开?')
if (answer) next()
else next(false)
})
onBeforeRouteUpdate((to, from, next) => {
// 处理参数更新
next()
})
总结:
路由守卫就是在页面跳转的各个阶段插入"检查逻辑",用
beforeEach做全局权限控制,用beforeEnter做路由级控制,用beforeRouteLeave等做组件级控制,实现灵活的导航控制。
路由元信息(Route Meta Fields)
什么是路由元信息?
想象一下,你有很多页面,每个页面有不同的"属性":
- 哪些页面需要登录才能访问?
- 哪些页面是管理员专属?
- 页面的标题是什么?
- 是否需要缓存组件?
- 页面切换时用什么动画?
这些"附加信息"不属于路径或组件本身,而是描述这个路由的"元数据"。
路由元信息(meta)就是:你可以在路由配置中添加任意自定义数据,供守卫、组件、布局等地方使用。
如何定义路由元信息?
在路由配置中,使用 meta 字段添加任意数据:
javascript
const routes = [
{
path: '/home',
component: Home,
meta: {
title: '首页',
requiresAuth: false,
keepAlive: true
}
},
{
path: '/user',
component: User,
meta: {
title: '用户中心',
requiresAuth: true,
roles: ['user', 'admin']
}
},
{
path: '/admin',
component: Admin,
meta: {
title: '后台管理',
requiresAuth: true,
roles: ['admin']
}
},
{
path: '/about',
component: About,
meta: { title: '关于我们' }
}
]
meta可以是任意结构的对象,你想加什么就加什么!
如何读取路由元信息?
在任何能访问到 $route 的地方,都可以通过 route.meta 读取。
1. 在路由守卫中使用(最常见)
示例:权限控制
javascript
router.beforeEach((to, from, next) => {
const isLogged = localStorage.getItem('token')
const userRole = localStorage.getItem('role') // 'user' 或 'admin'
// 检查目标页面是否需要登录
if (to.meta.requiresAuth) {
if (!isLogged) {
return next('/login')
}
// 检查角色权限
if (to.meta.roles && !to.meta.roles.includes(userRole)) {
return next('/forbidden')
}
}
next()
})
示例:设置页面标题
javascript
router.afterEach((to, from) => {
document.title = to.meta.title || '默认标题'
})
2. 在组件中使用
选项式 API:
javascript
<script>
export default {
created() {
console.log(this.$route.meta.title) // '用户中心'
console.log(this.$route.meta.requiresAuth) // true
}
}
</script>
组合式 API(推荐):
javascript
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
// 读取 meta 信息
const title = route.meta.title
const requiresAuth = route.meta.requiresAuth
</script>
<template>
<div>
<h1>{{ title }}</h1>
<p>需要登录:{{ requiresAuth ? '是' : '否' }}</p>
</div>
</template>
3. 在布局组件中使用
比如你想根据 meta.layout 决定使用哪个布局:
javascript
{
path: '/admin',
component: Admin,
meta: { layout: 'AdminLayout' }
}
在根组件中:
javascript
<template>
<component :is="layoutComponent">
<router-view />
</component>
</template>
<script setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import DefaultLayout from '@/layouts/Default.vue'
import AdminLayout from '@/layouts/Admin.vue'
const route = useRoute()
const layoutComponent = computed(() => {
const layout = route.meta.layout
if (layout === 'AdminLayout') return AdminLayout
return DefaultLayout
})
</script>
4. 配合 <router-view> 使用
<router-view> 会自动暴露 route 和 Component,你可以结合 meta 做动画或缓存判断:
javascript
<router-view v-slot="{ Component, route }">
<keep-alive>
<component :is="Component" v-if="route.meta.keepAlive" />
</keep-alive>
<component :is="Component" v-if="!route.meta.keepAlive" />
</router-view>
实际应用场景
| 场景 | 使用方式 |
|---|---|
| 权限控制 | 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 的核心能力,不再只是"会用",而是"懂它"。
现在,是时候打开你的项目,用这些知识去打造一个更智能、更健壮的前端应用了!
路由不止是路径,更是用户体验的起点。
