Vue3 路由配置和使用与讲解(超级详细)
引言:Vue 3 作为当前最受欢迎的前端框架之一,搭配其官方路由解决方案 Vue Router
,为我们提供了强大、灵活且易于上手的路由管理能力。
本篇文章将带你从零开始,超级详细地讲解 Vue 3 中 Vue Router 的安装、配置与实战用法。你将学会:
- 如何在 Vue 3 项目中安装并初始化
vue-router
; - 声明路由规则,实现组件与路径的映射;
- 使用
router-link
和编程式导航进行页面跳转; - 动态路由、嵌套路由、命名视图等高级用法;
- 路由守卫(导航守卫)的使用场景与最佳实践;
- 以及 Vue 3 组合式 API(
setup
)中如何正确使用路由。
无需担心基础是否扎实,我们将一步步深入,结合代码示例与图解,确保你不仅能“会用”,更能“理解”。
一.安装相关的组件(必不可少的)
简单的运行(最简单)
(一)安装 Vue Router
创建路由需要安装vue-router,可以通过 npm 进行安装。
打开终端:
在后端中输入
npm install vue-router@4
(二)创建文件夹与文件(路径)
在src中创建router文件夹与views文件夹:分别在里面创建相应的文件
其中router文件夹中的index.ts文件用于配置路由实例
index.ts:
// 把官方工具函数一次性引进来
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 时渲染 HomeViewpath: '/home',name: 'home',component: HomeView,children: [ // 嵌套路由:/home/list/123{path: 'list/:id', // 动态段,将来 this.$route.params.id 取值name: 'list',component: ListView}]},{ // 访问 /user 时渲染 UserViewpath: '/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的原来的代码:
import './assets/main.css'import { createApp } from 'vue'
import App from './App.vue'createApp(App).mount('#app')
main.ts的源代码
// 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
<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>
解释一下哈:
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.我们先导入
import { RouterView, RouterLink } from 'vue-router'
把官方提供的两个核心组件引进来:
RouterLink
:可点击的超链接,但会拦截浏览器默认跳转,改由 Vue Router 处理。
RouterView>
:占位符,真正渲染匹配到的页面组件。
2.声明式导航
<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.页面出口
<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?
你可能见过这样的网址:
https://example.com/#/home
https://example.com/#/about
注意那个 #
符号,它后面的部分叫做 hash(哈希值)。浏览器有一个特性:改变 hash 值不会导致页面刷新,而且浏览器会记录这个变化,支持前进后退。
当你点击一个路由链接(比如 <router-link to="/about">
),Vue Router 会把地址栏变成:
https://example.com/#/about
它只是修改了 URL 中 #
后面的部分。
因为只改了 hash,浏览器不会向服务器发送请求,页面不刷新。
Vue Router 监听 hash 的变化,一旦变了,就去加载对应的组件并显示。
配置方式如下:
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 捕获这个变化,动态加载对应的组件。
配置方法如下:
// 使用 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 都不一样:
/user/1
/user/2
/user/100
你不可能为每个用户都写一个路由,比如:
{ path: '/user/1', component: User }
{ path: '/user/2', component: User }
...
{ path: '/user/100', component: User }
这样写代码就太慢了,耗费时间,维护起来也崩溃。
动态路由就是:用一个路由规则,匹配一类结构相似的 URL。
/user/:id → 匹配 /user/1、/user/2、/user/abc
这里的 :id
是一个动态片段,它会捕获 URL 中对应的部分,传给组件使用。
动态路由怎么写?(语法)
在 Vue Router 中,使用冒号 :
来定义动态段。
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)
<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,推荐)
<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. 可选参数(用 ?
)
{ path: '/user/:id?' } // :id 可有可无
- 匹配:
/user
和/user/123
2. 零或多个(*
)和 一或多个(+
)
{ path: '/user/:id*' } // :id 可以出现 0 次或多次(很少用)
{ path: '/user/:id+' } // :id 至少出现 1 次
注意:
*
和+
是针对“路径段”的重复,不是字符重复。
拓展:
嵌套路由 + 动态路由
假设你有用户详情页,还有子页面:资料、订单、设置。
/user/1/profile
/user/1/orders
/user/1/settings
可以这样写:
{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
判断用户是否合法 - 是否有权限查看该页面
router.beforeEach((to, from, next) => {const userId = to.params.idif (userId === 'admin') {alert('禁止访问!')next('/error')} else {next()}
})
实际开发建议
命名规范
- 动态参数命名要有意义,比如:
:userId
而不是:id
:postId
而不是:p
{ path: '/:pathMatch(.*)*', component: NotFound }
- 提高代码可读性。
类型转换
动态参数是字符串,如果需要数字,记得转换:
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
[{ 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()
—— 跳转到新页面(类似点击链接)
这是最常用的编程式导航方法。
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,可以知道跳转是否成功:
router.push('/home').then(() => {console.log('跳转成功!')
}).catch(err => {console.log('跳转失败:', err)
})
跳转失败通常是:守卫阻止了跳转(比如没登录)。
2. router.replace()
—— 替换当前页面
和 push
类似,但不会在历史记录中留下记录。
router.replace('/login')
// 或
router.replace({ name: 'Login' })
效果:跳转后,用户点“后退”按钮,不会回到原来的页面(因为被替换了)。
应用场景:
- 登录页替换首页(防止登录后点后退还回到首页)
- 错误页面替换当前页
3. router.go(n)
—— 控制浏览器前进后退
相当于调用 window.history.go(n)
。
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>
)——推荐
<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. 避免重复导航到当前路由
router.push('/home') // 如果已经在 /home,会报错
Vue Router 会抛出一个 NavigationDuplicated
类型的错误。
✅ 解决方案:捕获错误或判断是否已经是当前页。
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, ...)
(组合式)
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
—— 全局前置守卫(最常用)
在每次路由跳转前执行,可以决定是否放行。
基本语法:
router.beforeEach((to, from, next) => {// to: 即将进入的路由// from: 当前离开的路由// next: 必须调用,决定如何导航
})
示例:登录权限控制
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
类似,但在所有组件内守卫和异步组件加载完毕后才触发。
适用于:需要等所有准备工作完成后再确认跳转。
router.beforeResolve((to, from, next) => {// 例如:检查页面权限、预加载数据等next()
})
afterEach
—— 全局后置钩子(不用 next
)
在路由跳转完成后执行,不能阻止跳转,常用于:
- 页面埋点(统计 PV)
- 修改页面标题
- 关闭 loading 动画
router.afterEach((to, from) => {document.title = to.meta.title || '默认标题'console.log('页面已跳转')
})
它没有
next()
,只是“事后通知”。
三、组件内守卫(In-Component Guards)
写在组件内部,用于控制该组件的进入、离开或更新。
1. beforeRouteEnter
—— 进入组件前
export default {beforeRouteEnter(to, from, next) {// 注意:此时组件实例还未创建,不能访问 `this`next(vm => {// 在 `next` 的回调中可以访问组件实例 `vm`console.log(vm) // 组件实例})}
}
常用于:进入前获取数据。
2. beforeRouteUpdate
—— 组件被复用时(如动态路由 /user/1
→ /user/2
)
beforeRouteUpdate(to, from, next) {// 组件实例已存在,可以访问 `this`this.fetchUserData(to.params.id) // 重新加载用户数据next()
}
3. beforeRouteLeave
—— 离开组件前
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. 避免无限重定向
router.beforeEach((to, from, next) => {next('/login') // ❌ 错误:每次都重定向,死循环
})
正确写法:
if (to.path !== '/login') {next('/login')
} else {next()
}
3. beforeRouteEnter
不能访问 this
因为组件还没创建。需要用 next(vm => { ... })
回调。
4. 组合式 API 中如何使用?
Vue 3 推荐使用 setup()
或 <script setup>
,可以用以下方式:
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
字段添加任意数据:
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. 在路由守卫中使用(最常见)
示例:权限控制
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()
})
示例:设置页面标题
router.afterEach((to, from) => {document.title = to.meta.title || '默认标题'
})
2. 在组件中使用
选项式 API:
<script>
export default {created() {console.log(this.$route.meta.title) // '用户中心'console.log(this.$route.meta.requiresAuth) // true}
}
</script>
组合式 API(推荐):
<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
决定使用哪个布局:
{path: '/admin',component: Admin,meta: { layout: 'AdminLayout' }
}
在根组件中:
<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.layoutif (layout === 'AdminLayout') return AdminLayoutreturn DefaultLayout
})
</script>
4. 配合 <router-view>
使用
<router-view>
会自动暴露 route
和 Component
,你可以结合 meta
做动画或缓存判断:
<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
字段不会自动合并。你需要手动处理。
{path: '/user',meta: { requiresAuth: true },children: [{ path: 'profile', component: Profile } // 不会继承 requiresAuth]
}
解决方案:在守卫中递归检查所有匹配的路由:
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
提供类型:
import 'vue-router'declare module 'vue-router' {interface RouteMeta {title?: stringrequiresAuth?: booleanroles?: string[]keepAlive?: boolean[key: string]: any // 允许其他自定义字段}
}
这样在 route.meta.xxx
时就有智能提示了。
总结一句话:
路由元信息(meta)是一个“自定义数据容器”,你可以在路由配置中添加任意信息(如权限、标题、缓存等),然后在守卫、组件、布局中读取它,实现灵活的页面控制和逻辑判断。
路由,看似只是“页面跳转”,实则是整个应用的骨架与脉络。一个好的路由设计,能让代码更清晰、权限更安全、用户体验更流畅。
希望这篇博客能帮你真正掌握 Vue Router 的核心能力,不再只是“会用”,而是“懂它”。
现在,是时候打开你的项目,用这些知识去打造一个更智能、更健壮的前端应用了!
路由不止是路径,更是用户体验的起点。