vue-router 怎么获取当前路由?
在Vue项目里,路由管理基本离不开vue-router,不管是做权限控制、导航高亮,还是埋点统计,经常需要知道“当前用户在哪个页面”——也就是获取当前路由信息,那vue-router到底怎么获取当前路由?不同场景下有啥不一样的方法?今天把常见情况拆开来聊聊。
先搞懂“当前路由”是个啥对象
vue-router里的“当前路由”,对应一个路由对象(Route Object),这个对象里存着当前页面路由的核心信息,
path:当前页面的路径(比如/home);name:路由配置时定义的名称(如果配了name: 'Home',这里就是'Home');params:动态路由参数(比如/user/:id对应的id值);query:URL上的查询参数(比如?keyword=vue对应的{ keyword: 'vue' });meta:路由元信息(自定义的配置,比如meta: { requireAuth: true }用来做权限标记)。
简单说,这个对象就是当前页面路由的“身份证”,里面的信息能帮我们判断页面状态、做逻辑分支。
组件内部怎么拿当前路由?
大部分业务逻辑写在组件里,所以组件内获取当前路由是最常见的场景,Vue2和Vue3的写法有差异,分开说:
Vue2(选项式API):用this.$route
在Vue2的组件里(比如.vue文件的methods、created这些钩子中),直接通过this.$route就能拿到当前路由对象,注意和this.$router区分开:$router是路由实例(用来做push、replace跳转),$route才是当前路由对象。
举个例子:做一个需要判断页面的组件——如果当前在“关于我们”页面,就显示特殊文案:
<template>
<div>
<p v-if="isAboutPage">这是关于我们的专属内容</p>
</div>
</template>
<script>
export default {
name: 'MyComponent',
computed: {
isAboutPage() {
// 判断当前路由的path是否是/about
return this.$route.path === '/about'
}
}
}
</script>
再比如,从列表页跳转到详情页时,需要用params传ID,在详情页组件的created钩子拿参数:
<script>
export default {
created() {
const productId = this.$route.params.id
this.fetchProductDetail(productId) // 调用接口拿详情数据
},
methods: {
fetchProductDetail(id) { /* ... */ }
}
}
</script>
Vue3(组合式API):用useRoute()
Vue3的组合式API更强调“按需导入”,所以要从vue-router里导入useRoute函数,在setup语法糖(或setup()函数)里用。
举个搜索页的例子:URL里有?keyword=xxx,页面加载时要把搜索关键词回显到输入框:
<template>
<input v-model="searchKeyword" placeholder="请输入关键词" />
</template>
<script setup>
import { useRoute, watch } from 'vue-router'
import { ref, computed } from 'vue'
const route = useRoute() // 拿到当前路由对象
// 初始化时从query里拿keyword
const searchKeyword = ref(route.query.keyword || '')
// 监听路由query变化(比如从其他页面带参数跳过来)
watch(
() => route.query,
(newQuery) => {
searchKeyword.value = newQuery.keyword || ''
},
{ immediate: true }
)
</script>
这里要注意:useRoute()必须在 setup 上下文里调用(比如<script setup>或setup()函数内),如果在普通函数里直接调用会报错,因为依赖Vue的响应式上下文。
路由守卫里怎么获取当前路由?
路由守卫是控制页面跳转权限、做导航拦截的关键,不管是全局守卫、路由独享守卫,还是组件内守卫,都能拿到“目标路由”(也就是即将进入的当前路由)和“来源路由”。
全局守卫:beforeEach、beforeResolve
全局守卫作用于所有路由跳转,参数里的to就是即将进入的目标路由(相当于“当前要去的路由”),from是“当前离开的路由”。
比如做全局权限控制:某些页面需要登录后才能进,在main.js里写:
import { createRouter, createWebHistory } from 'vue-router'
import store from './store' // 假设用Vuex/Pinia存用户登录状态
const router = createRouter({
history: createWebHistory(),
routes: [/* 路由配置 */]
})
router.beforeEach((to, from, next) => {
// 检查目标路由是否需要登录(通过meta字段标记)
if (to.meta.requireAuth) {
const isLogin = store.state.user.isLogin // 假设存了登录状态
if (isLogin) {
next() // 已登录,放行
} else {
next('/login') // 没登录,跳登录页
}
} else {
next() // 不需要登录,直接放行
}
})
这里to就是即将进入的路由对象,可以访问to.path、to.meta这些属性做判断。
路由独享守卫:beforeEnter
在单个路由的配置里,可以写beforeEnter守卫,参数同样是to、from、next,比如某个路由需要动态参数校验:
const routes = [
{
path: '/order/:orderId',
name: 'OrderDetail',
component: OrderDetail,
beforeEnter: (to, from, next) => {
// 检查orderId是否是合法格式(比如数字)
const orderId = to.params.orderId
if (/^\d+$/.test(orderId)) {
next()
} else {
next('/404') // 参数不合法,跳404
}
}
}
]
这里to.params.orderId就是当前要进入的订单详情页的参数,通过beforeEnter提前拦截非法参数。
组件内守卫:beforeRouteEnter、beforeRouteUpdate等
组件内守卫写在组件的选项里(Vue2)或组合式API的onBeforeRouteUpdate(Vue3),比如beforeRouteEnter在组件实例创建前触发,此时this还没生成,所以要通过to参数拿路由信息:
Vue2例子(组件内守卫):
<script>
export default {
name: 'Product',
beforeRouteEnter(to, from, next) {
// 这里不能用this,因为组件还没创建
// 但可以通过to拿到目标路由的query参数
const tab = to.query.tab || 'info'
next(vm => {
// vm是组件实例,创建后执行
vm.activeTab = tab // 把tab参数传给组件的activeTab
})
}
}
</script>
Vue3例子(组合式API的onBeforeRouteUpdate):
<script setup>
import { onBeforeRouteUpdate } from 'vue-router'
import { ref } from 'vue'
const activeTab = ref('info')
onBeforeRouteUpdate((to, from) => {
// 路由参数变化时(比如从/product/1?tab=info 跳到 /product/1?tab=comment)
activeTab.value = to.query.tab || 'info'
})
</script>
组件内守卫的核心是:在路由进入、更新、离开的不同阶段,通过to参数获取当前(或即将进入的)路由信息,配合组件逻辑做处理。
非组件场景怎么拿当前路由?(比如工具函数、状态管理里)
有时候逻辑不在组件里,比如写在Vuex的action、Pinia的store,或者单独的工具函数里,这时候要获取当前路由,得导入路由实例,然后用router.currentRoute。
Vue3 例子(Pinia里获取当前路由):
假设在store/user.js里,需要根据当前路由判断是否要跳转:
import { defineStore } from 'pinia'
import { useRouter } from 'vue-router'
export const useUserStore = defineStore('user', {
actions: {
logout() {
// 清除登录态...
const router = useRouter()
const currentRoute = router.currentRoute.value // 注意是ref,要.value
// 如果当前在个人中心页面,退出后跳首页;否则跳登录页
if (currentRoute.path === '/profile') {
router.push('/')
} else {
router.push('/login')
}
}
}
})
单独工具函数例子:
写一个checkRouteAuth.js工具函数,判断当前路由是否需要权限:
import { useRouter } from 'vue-router'
export function checkRouteAuth() {
const router = useRouter()
const currentRoute = router.currentRoute.value
return currentRoute.meta.requireAuth || false
}
然后在组件里用:
<script setup>
import { checkRouteAuth } from '@/utils/checkRouteAuth'
import { onMounted } from 'vue'
onMounted(() => {
const needAuth = checkRouteAuth()
if (needAuth && !isLogin()) { // 假设isLogin是判断登录的函数
// 跳登录页...
}
})
</script>
这里要注意:router.currentRoute在Vue3中是响应式的ref对象,所以必须通过.value才能拿到最新的路由对象,如果直接写router.currentRoute.path,拿到的是初始值,不会随路由变化更新。
拿到当前路由能干嘛?这些场景超实用
获取当前路由不是目的,而是为了解决实际业务问题,举几个常见场景,理解了这些,你就知道为啥要费心思拿路由信息了:
页面权限控制
后台管理系统很典型:不同角色(管理员、普通员工)能访问的页面不一样,在路由的meta里配role,然后结合全局守卫或组件内逻辑判断:
// 路由配置
{
path: '/admin/dashboard',
name: 'AdminDashboard',
component: AdminDashboard,
meta: {
requireAuth: true,
role: ['admin'] // 只有管理员能进
}
}
// 全局守卫判断
router.beforeEach((to, from, next) => {
if (to.meta.role) {
const userRole = store.state.user.role
if (to.meta.role.includes(userRole)) {
next()
} else {
next('/403') // 权限不足页面
}
}
})
动态导航高亮
网站头部或侧边栏的菜单,需要根据当前路由“高亮”对应的选项,比如用v-for循环菜单,根据route.name匹配:
<template>
<nav>
<ul>
<li
v-for="menu in menuList"
:key="menu.name"
:class="{ active: route.name === menu.name }"
>
{{ menu.title }}
</li>
</ul>
</nav>
</template>
<script setup>
import { useRoute } from 'vue-router'
import { ref } from 'vue'
const route = useRoute()
const menuList = ref([
{ name: 'Home', title: '首页' },
{ name: 'About', title: '关于我们' },
{ name: 'Contact', title: '联系我们' }
])
</script>
<style scoped>
.active { color: red; }
</style>
埋点统计用户行为
比如统计用户在每个页面的停留时间,进入页面时记录时间,离开时计算时长并上报:
<script setup>
import { useRoute, onBeforeRouteLeave } from 'vue-router'
import { onMounted } from 'vue'
const route = useRoute()
let enterTime = 0
onMounted(() => {
enterTime = Date.now() // 记录进入时间
})
onBeforeRouteLeave((to, from) => {
const stayTime = Date.now() - enterTime
// 上报停留时间:当前路由path + 时长
reportStayTime(from.path, stayTime)
})
function reportStayTime(path, time) {
// 调用接口上报,
// axios.post('/api/analytics', { path, time })
}
</script>
页面级缓存与销毁
用keep-alive缓存组件时,有时候需要根据路由决定是否缓存,比如列表页需要缓存,详情页不需要:
<template>
<router-view v-slot="{ Component }">
<keep-alive :include="keepAliveComponents">
<component :is="Component" />
</keep-alive>
</router-view>
</template>
<script setup>
import { useRoute, watch } from 'vue-router'
import { ref } from 'vue'
const keepAliveComponents = ref([])
const route = useRoute()
watch(
() => route.name,
(newName) => {
// 假设列表页路由name是'ProductList',需要缓存
if (newName === 'ProductList') {
keepAliveComponents.value = ['ProductList']
} else {
keepAliveComponents.value = []
}
},
{ immediate: true }
)
</script>
常见问题:为啥有时候拿不到路由?咋解决?
实际开发中,获取路由容易踩坑,列几个高频问题和解法:
报错“this.$route is undefined”
原因:组件不是路由组件(即没有通过<router-view>渲染,而是直接用<MyComponent>写死在模板里),路由实例的$route、$router只会注入到路由组件中。
解决:确保组件是通过路由配置渲染的(在routes里配了对应的component),如果是普通组件需要路由信息,就用useRoute()(Vue3)或者把路由信息通过props传进去。
路由参数变了,但组件没刷新
原因:Vue路由默认复用相同组件(比如从/user/1跳到/user/2,组件实例不会销毁重建),所以created、mounted这些钩子不会重新执行,导致拿不到新参数。
解决:
-
Vue2:用
beforeRouteUpdate组件内守卫,监听参数变化; -
Vue3:用
onBeforeRouteUpdate组合式API,或者watch路由的params/query:<script setup> import { useRoute, watch } from 'vue-router' const route = useRoute() watch( () => route.params.id, (newId) => { fetchData(newId) // 参数变化时重新请求数据 }, { immediate: true } ) </script>
router.currentRoute.value拿的是旧值
原因:在Vue3中,router.currentRoute是ref对象,必须在响应式上下文(如setup、生命周期钩子、watch回调)里访问.value,如果在普通函数或异步回调里直接拿,可能因为时机问题拿到旧值。
解决:确保访问router.currentRoute.value时,是在响应式环境中,比如用watch监听router.currentRoute,或者在setup里先赋值给变量:
const router = useRouter() const currentRoute = computed(() => router.currentRoute.value) // 然后用currentRoute.value.path
获取vue-router当前路由的核心思路是:根据场景选方法(组件内用$route/useRoute,守卫里用to参数,非组件场景用router.currentRoute),理解路由对象的结构,再结合业务场景(权限、导航、埋点等)做逻辑扩展,只要把这些细节理清楚,不管是Vue2还是Vue3项目,都能灵活拿到当前路由,让页面逻辑更丝滑~要是你在开发中遇到其他路由相关的问题,评论区随时聊聊~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网



