先搞懂,Vue Router与当前路由是什么?
做Vue项目开发时,路由管理是绕不开的环节,而“知道当前用户在哪个路由页面”更是高频需求——比如导航栏要高亮当前页、根据路由参数发起接口请求、权限控制时判断路径…那在Vue Router里到底怎么获取当前路由信息呢?这篇文章从基础到场景,把常用方法和坑点一次性讲透~
Vue Router是Vue生态里管理单页面应用(SPA)路由的核心工具,它能让我们通过不同URL路径,渲染对应的组件、传递参数,而“当前路由”本质是个路由对象,里面存着当前页面的关键信息,常见的有这些:
path:当前路由的路径(比如/user/123)params:动态路由参数(比如/user/:id里的{ id: '123' })query:URL上的查询参数(比如?name=张三对应的{ name: '张三' })meta:路由元信息(配置在路由规则里的自定义数据,比如权限标识requiresAuth: true)
简单说,获取当前路由,就是拿到包含这些信息的对象~接下来看具体怎么拿!
选项式API里用 this.$route
如果你用的是Vue 2,或者Vue 3但写的是选项式组件(比如export default { data() {}, methods: {} }这种写法),直接在组件里通过 this.$route 就能拿到当前路由对象。
举个实际开发的例子:假设要做“导航栏高亮”,在mounted钩子或者methods里判断路径:
<template>
<nav>
<a :class="{ active: isHome }">首页</a>
<a :class="{ active: isUser }">用户页</a>
</nav>
</template>
<script>
export default {
computed: {
isHome() {
return this.$route.path === '/'; // 对比当前路径是否是首页
},
isUser() {
return this.$route.path.startsWith('/user'); // 匹配用户页路径
}
}
}
</script>
这里要注意两个点:
this的指向:必须在Vue组件的实例上下文里用(比如methods、computed、生命周期钩子),如果用箭头函数定义方法,this会丢失,变成undefined!- 路由对象是响应式的:当路由变化时(比如从
/user/1跳到/user/2),this.$route会自动更新,所以基于它的计算属性、绑定的class也会自动响应变化~
组合式API里用 useRoute
如果你的项目是Vue 3 + Composition API(尤其是用<script setup>语法糖),获取路由得用组合式API提供的useRoute,步骤很简单:
- 从
vue-router里导入useRoute; - 在
setup函数(或<script setup>)里调用useRoute,得到路由对象。
看例子:在用户详情页,根据路由参数id发请求(用<script setup>写法):
<template>
<div v-if="userInfo">用户{{ userInfo.name }}的详情</div>
</template>
<script setup>
import { onMounted, watch } from 'vue'
import { useRoute } from 'vue-router'
import { fetchUser } from '@/api/user' // 假设的接口请求函数
const route = useRoute() // 获取当前路由对象
const userInfo = ref(null)
// 方式1:mounted时根据参数请求
onMounted(() => {
const userId = route.params.id // 取动态路由参数id
fetchUser(userId).then(res => {
userInfo.value = res.data
})
})
// 方式2:监听路由参数变化(比如从/user/1跳转到/user/2时自动重新请求)
watch(
() => route.params.id, // 监听params里的id变化
(newId) => {
fetchUser(newId).then(res => {
userInfo.value = res.data
})
},
{ immediate: true } // 组件加载时立即执行一次
)
</script>
这里的route和选项式API里的this.$route作用一样,也是响应式的,但要注意:不能在组件外(比如单独的js工具文件)直接用useRoute,因为它依赖Vue的组件上下文,必须在组件的setup或<script setup>里调用~
全局场景用 router.currentRoute
如果你的代码不在组件里(比如写了个全局的工具函数,或者在路由守卫之外的地方需要路由信息),这时候得用VueRouter实例的currentRoute属性。
回忆下VueRouter的初始化:我们通常会在router/index.js里创建路由实例:
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import routes from './routes'
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
这个router实例上的currentRoute是个ref对象(Vue 3的响应式语法),所以要拿到实际的路由对象,得取router.currentRoute.value。
举个场景:在全局的权限拦截工具里,判断当前路径是否需要登录:
// utils/permission.js
import router from '@/router' // 导入上面创建的router实例
export function checkAuth() {
const currentRoute = router.currentRoute.value // 取当前路由对象
if (currentRoute.meta.requiresAuth && !isLogin()) { // 假设isLogin是判断登录态的函数
return false // 没登录且需要权限,拦截
}
return true
}
这里要注意异步问题:路由变化是异步的,如果在导航过程中(比如刚调用router.push)立刻获取router.currentRoute.value,可能拿到的是旧路由,这种情况需要等导航完成,或者用nextTick处理(后面场景部分会详细讲)~
导航后获取“最新”路由
比如点击按钮跳转到新页面后,要立刻获取新路由的信息(比如统计埋点、修改页面标题),但router.push是异步操作,直接在push后拿路由可能拿到旧值:
// 错误示范:可能拿到旧路由
router.push('/user/123')
console.log(this.$route.path) // 可能还是原来的路径!
解决方法有两种:
- 用
router.push的回调:router.push支持传回调,导航完成后执行:
router.push('/user/123', () => {
console.log(this.$route.path) // 此时是新路径'/user/123'
})
- 结合
nextTick(Vue的异步更新队列):
import { nextTick } from 'vue'
router.push('/user/123')
await nextTick() // 等Vue更新完响应式数据(包括路由)
console.log(this.$route.path) // 新路径
路由守卫里的路由信息
Vue Router的路由守卫(比如全局守卫beforeEach、组件内守卫beforeRouteEnter)里,本身就会传入to(目标路由)和from(当前路由)这两个参数,直接用就行~
举个全局守卫的例子,做权限控制:
// router/index.js
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isLogin()) { // to是目标路由,判断是否需要权限
next('/login') // 没登录就跳登录页
} else {
next() // 放行
}
})
再看组件内守卫beforeRouteUpdate(当路由参数变化,但组件复用的时候触发,比如/user/1跳到/user/2):
<script>
export default {
beforeRouteUpdate(to, from) {
console.log('旧路由:', from.path)
console.log('新路由:', to.path)
this.fetchData(to.params.id) // 根据新参数重新请求数据
}
}
</script>
注意:beforeRouteEnter里拿不到this(因为组件还没创建),所以如果要在进入组件前用路由信息,得通过next传回调:
<script>
export default {
beforeRouteEnter(to, from, next) {
next(vm => { // vm是组件实例
vm.initData(to.params.id) // 用vm访问组件方法
})
}
}
</script>
监听路由变化做响应
有时候路由变化时,要自动执行逻辑(比如参数变化重新发请求、页面切换时销毁定时器),这时候可以监听路由对象的变化:
- 选项式API里,用
watch监听$route:
<script>
export default {
watch: {
'$route.params.id'(newId, oldId) { // 监听params里的id变化
this.fetchData(newId)
}
}
}
</script>
- 组合式API里,用
watch监听useRoute拿到的route:
<script setup>
import { watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
watch(route, (newRoute, oldRoute) => {
console.log('路由从', oldRoute.path, '变到', newRoute.path)
// 执行其他逻辑,比如根据newRoute.query.page重新请求列表
}, { deep: true }) // 如果要监听路由对象内部属性变化,开deep(不过一般路由对象是整体替换,所以也可以不开)
</script>
问题1:为什么this.$route是undefined?
大概率是这两个原因:
- 组件没被Vue Router管理:比如这个组件不是通过
<router-view>渲染的,而是直接写在App.vue里的静态组件,这时组件上下文没有$route; this指向错误:比如在箭头函数里用this.$route,导致this不是组件实例,解决方法是把函数改成普通函数,或者用getCurrentInstance获取组件实例(但尽量优先用选项式的写法避免this问题)。
问题2:路由变了,但页面数据没更新?
比如路由参数从/user/1变到/user/2,但组件里的数据还是用户1的,这是因为组件复用了(Vue Router默认策略:相同组件复用,不销毁重建),所以mounted不会重新执行,解决方法:
- 用
beforeRouteUpdate守卫,在路由变化时主动更新数据; - 用
watch监听路由参数变化,触发数据请求; - 给
<router-view>加key,强制销毁重建组件(但性能略差,不推荐除非特殊情况)。
问题3:router.currentRoute.value拿到的是旧路由?
因为router.push等导航方法是异步的,路由更新需要时间,如果要在导航后立刻拿新路由,得等导航完成:
// 正确做法:等push完成后再拿
router.push('/user/123').then(() => {
console.log(router.currentRoute.value.path) // 新路径
})
或者用await配合nextTick:
await router.push('/user/123')
await nextTick()
console.log(router.currentRoute.value.path)
问题4:解构路由属性后,响应式失效?
比如在组合式API里这样写:
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
const { path } = route // 这里解构后,path不是响应式的!
watch(path, () => { // 永远监听不到变化
console.log('路径变了')
})
</script>
原因是解构会破坏响应式,解决方法:直接用route.path,或者监听整个route对象:
// 正确写法:监听route或者route的属性函数
watch(
() => route.path,
(newPath) => {
console.log('路径变了:', newPath)
}
)
选对方法,场景为王
获取当前路由的核心逻辑是拿到路由对象,但不同Vue版本(Vue 2/3)、不同代码位置(组件内/外)、不同场景(导航后/守卫里)对应的方法不同:
- 组件内(选项式)→
this.$route - 组件内(组合式)→
useRoute - 组件外(全局逻辑)→
router.currentRoute.value
同时要注意异步更新和响应式监听的细节,避免拿到旧数据或监听失效,实际开发中,先明确自己的代码环境(是选项式还是组合式?在组件内还是外?),再选对应的方法,遇到问题时对照上面的场景和坑点排查,基本就能搞定~
如果想更深入,建议去看Vue Router官方文档里的路由对象章节,里面对路由对象的属性、方法有更权威的解释~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网



发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。