vue router怎么获取path?
在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的方式略有不同,但核心都是用to
和from
这两个参数。
全局守卫(以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为例)
组件内守卫是写在组件选项里的,比如beforeRouteEnter
、beforeRouteUpdate
、beforeRouteLeave
,这里要注意,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
,参数也是to
、from
、next
,用法和全局守卫类似:
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#detail
,path
就是/article
。$route.fullPath
:包含路径、查询参数、哈希,上面的例子里fullPath
就是/article?category=vue#detail
。
所以获取的时候,得先想清楚需求:如果只需要纯粹的路径(比如判断是/home还是/about),用path
;如果要包含参数和锚点的完整路径(比如做页面缓存的key,或者分享链接),就得用fullPath
。
举个实际例子,做搜索页面的筛选,用户选了筛选条件后url变成/search?sort=hot&page=2
,这时候path
是/search
,fullPath
是/search?sort=hot&page=2
,如果在组件里要根据筛选参数做逻辑,光看path
是不够的,得结合query
,但如果只是判断用户在不在搜索页,用path
就够。
为什么有时候获取不到path?常见问题排查
遇到this.$route.path
是undefined
或者拿不到预期值,大概率是这几个原因:
组件没被路由管理
如果组件是直接用<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
,看看里面的path
、matched
等属性是否符合预期,再回头检查路由配置。
获取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前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。