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

vue router怎么获取path?

terry 15小时前 阅读数 14 #Vue

在Vue项目里,路由管理是很重要的一环,而获取当前路由的path更是经常会用到的操作——比如判断用户当前在哪个页面来展示不同导航、做权限拦截,或者统计页面访问情况,那vue router到底怎么获取path?不同场景下有啥要注意的地方?今天就把这些问题拆开来聊聊。

组件内部怎么获取当前路由的path?

在Vue组件里,要获取当前路由的path,得先分清$route$router的区别,简单说,$router是Vue Router的实例,用来做编程式导航(比如this.$router.push('/xxx'));而$route当前活跃的路由对象,里面存着当前路由的信息,像path、params、query这些都在$route里。

所以在组件里获取path,直接用this.$route.path就行,举个例子,在一个Vue组件的生命周期钩子或者方法里:

<template>
  <div>
    <!-- 模板里直接渲染 -->
    当前路径:{{ $route.path }}
  </div>
</template>
<script>
export default {
  mounted() {
    // 生命周期里打印
    console.log('当前路径是:', this.$route.path)
  },
  methods: {
    checkPath() {
      // 方法里使用
      if (this.$route.path === '/home') {
        // 做些首页相关的操作
      }
    }
  }
}
</script>

这里要注意,只有当组件被<router-view>管理(也就是通过路由配置渲染的组件),this.$route才会有值,要是普通组件没被路由渲染,直接用this.$route会拿到undefined,这时候得检查组件是否在路由配置里,或者有没有被正确挂载到路由视图中。

路由守卫中如何获取path?

路由守卫是控制路由跳转权限、处理导航逻辑的关键,这里面获取path主要靠守卫的参数,路由守卫分全局守卫、路由独享守卫、组件内守卫,不同守卫里获取path的方式略有不同,但核心都是用tofrom这两个参数。

全局守卫(以router.beforeEach为例)

全局守卫会在每次路由跳转前触发,参数to即将进入的目标路由对象from当前要离开的路由对象,所以要获取目标路径,用to.path;获取来源路径用from.path,比如做全局权限拦截:

const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
  console.log('要去的页面:', to.path)
  console.log('从哪个页面来:', from.path)
  // 假设某些页面需要登录
  if (to.path === '/profile' && !isLogin()) {
    next('/login') // 没登录就跳登录页
  } else {
    next() // 正常放行
  }
})

组件内守卫(以beforeRouteEnter为例)

组件内守卫是写在组件选项里的,比如beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave,这里要注意,beforeRouteEnter执行时,组件实例(this)还没创建,所以不能用this.$route,得通过to参数获取path:

<script>
export default {
  beforeRouteEnter(to, from, next) {
    // 这里this是undefined,所以用to.path
    console.log('即将进入的页面path:', to.path)
    next()
  },
  beforeRouteUpdate(to, from, next) {
    // 路由参数变化时触发(/user/:id 从/user/1跳到/user/2)
    // 这时候组件实例已存在,可以用this.$route.path,也能用to.path
    console.log('原来的path:', from.path)
    console.log('新的path:', to.path)
    console.log('当前实例的path:', this.$route.path)
    next()
  },
  beforeRouteLeave(to, from, next) {
    // 离开当前组件时,from是当前路由,to是目标路由
    console.log('要离开的页面path:', from.path)
    console.log('要去的页面path:', to.path)
    next()
  }
}
</script>

路由独享守卫(beforeEnter)

在路由配置里,给单个路由配置beforeEnter,参数也是tofromnext,用法和全局守卫类似:

const router = new VueRouter({
  routes: [
    {
      path: '/secret',
      component: SecretComponent,
      beforeEnter: (to, from, next) => {
        console.log('要进入secret页面,path是:', to.path)
        // 做权限判断...
        next()
      }
    }
  ]
})

path和fullPath有什么区别?获取时要注意什么?

不少同学会把$route.path$route.fullPath搞混,其实它们代表的是路由不同部分的信息:

  • $route.path只是路径部分,不包含查询参数(query)和哈希(hash),比如访问的是/article?category=vue#detailpath就是/article
  • $route.fullPath包含路径、查询参数、哈希,上面的例子里fullPath就是/article?category=vue#detail

所以获取的时候,得先想清楚需求:如果只需要纯粹的路径(比如判断是/home还是/about),用path;如果要包含参数和锚点的完整路径(比如做页面缓存的key,或者分享链接),就得用fullPath

举个实际例子,做搜索页面的筛选,用户选了筛选条件后url变成/search?sort=hot&page=2,这时候path/searchfullPath/search?sort=hot&page=2,如果在组件里要根据筛选参数做逻辑,光看path是不够的,得结合query,但如果只是判断用户在不在搜索页,用path就够。

为什么有时候获取不到path?常见问题排查

遇到this.$route.pathundefined或者拿不到预期值,大概率是这几个原因:

组件没被路由管理

如果组件是直接用<MyComponent>这种方式渲染,而不是通过<router-view>加载的,那这个组件不属于路由系统,this.$route自然是undefined,解决方法是确保组件在路由配置里,并且通过路由跳转(比如this.$router.push)或者<router-link>来渲染。

Vue Router没正确安装

在Vue项目里,要先通过Vue.use(VueRouter)安装插件,然后创建router实例并注入到Vue根实例,如果没做这步,整个路由系统没初始化,$route$router都不存在,检查main.js里的配置:

import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
import routes from './routes'
Vue.use(VueRouter) // 必须先use,安装插件
const router = new VueRouter({ routes })
new Vue({
  router, // 注入到根实例
  render: h => h(App)
}).$mount('#app')

异步组件加载时机问题

如果用了异步组件(比如component: () => import('./views/About.vue')),在组件还没加载完成时,可能暂时拿不到$route,这种情况可以把逻辑放到mounted钩子或者更晚的阶段,等组件完全渲染后再获取。

路由配置错误

比如路由的path写错了,或者嵌套路由配置不对,导致实际渲染的路由和预期不一致,这时候可以在浏览器控制台打印this.$route,看看里面的pathmatched等属性是否符合预期,再回头检查路由配置。

获取path在实际项目中有哪些应用?

知道怎么获取path后,在项目里能解决不少实际问题,举几个常见场景:

导航栏高亮

网站的导航栏需要根据当前页面高亮对应的选项,这时候就可以用$route.path判断。

<template>
  <nav>
    <a 
      :class="{ active: $route.path === '/home' }" 
      href="#/home"
    >首页</a>
    <a 
      :class="{ active: $route.path === '/article' }" 
      href="#/article"
    >文章</a>
  </nav>
</template>
<style>
.active { color: red; }
</style>

权限控制

某些页面(比如个人中心、订单页)需要用户登录后才能访问,这时候在全局守卫里判断to.path,如果是受保护的路径且用户未登录,就跳转到登录页:

router.beforeEach((to, from, next) => {
  const needAuth = ['/profile', '/order'].includes(to.path)
  if (needAuth && !isLogin()) {
    next('/login?redirect=' + to.path) // 把目标path传过去,登录后跳回来
  } else {
    next()
  }
})

页面埋点统计

统计用户访问了哪些页面,就可以在路由守卫里记录to.path,比如结合百度统计或谷歌分析:

router.afterEach((to) => {
  // 假设用百度统计的_paq.push
  window._paq = window._paq || [];
  window._paq.push(['setCustomUrl', to.path]);
  window._paq.push(['trackPageView']);
})

动态修改页面标题 document.title)可以根据当前路由的path变化,在路由守卫或者组件mounted里设置:

router.beforeEach((to, from, next) => {
  const titleMap = {
    '/home': '首页 - 我的网站',
    '/article': '文章列表 - 我的网站'
  }
  document.title = titleMap[to.path] || '我的网站'
  next()
})

缓存组件逻辑

在使用<keep-alive>缓存组件时,可能需要根据path决定是否缓存,比如只缓存首页和文章页:

<template>
  <keep-alive :include="keepAliveComponents">
    <router-view></router-view>
  </keep-alive>
</template>
<script>
export default {
  computed: {
    keepAliveComponents() {
      const path = this.$route.path
      return path === '/home' || path === '/article' ? ['Home', 'Article'] : []
    }
  }
}
</script>

vue router获取path的核心是操作`$route`对象,不同场景下(组件内、路由守卫里)要结合对应的API和参数来拿,同时得注意path和fullPath的区别,避免因为需求理解错导致bug,实际项目里,获取path能帮我们做导航、权限、统计这些关键功能,把这些用法吃透,路由这块的开发会顺很多~要是你还有其他关于vue router的疑问,比如动态路由参数怎么拿、路由传参有哪些方式,评论区可以聊聊~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

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

热门