Code前端首页关于Code前端联系我们

vue-router 怎么获取当前路由?

terry 6小时前 阅读数 11 #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文件的methodscreated这些钩子中),直接通过this.$route就能拿到当前路由对象,注意和this.$router区分开:$router是路由实例(用来做pushreplace跳转),$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的响应式上下文。

路由守卫里怎么获取当前路由?

路由守卫是控制页面跳转权限、做导航拦截的关键,不管是全局守卫、路由独享守卫,还是组件内守卫,都能拿到“目标路由”(也就是即将进入的当前路由)和“来源路由”。

全局守卫:beforeEachbeforeResolve

全局守卫作用于所有路由跳转,参数里的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.pathto.meta这些属性做判断。

路由独享守卫:beforeEnter

在单个路由的配置里,可以写beforeEnter守卫,参数同样是tofromnext,比如某个路由需要动态参数校验:

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提前拦截非法参数。

组件内守卫:beforeRouteEnterbeforeRouteUpdate

组件内守卫写在组件的选项里(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,组件实例不会销毁重建),所以createdmounted这些钩子不会重新执行,导致拿不到新参数。

解决:

  • 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.currentRouteref对象,必须在响应式上下文(如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前端网发表,如需转载,请注明页面地址。

发表评论:

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

热门