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前端网发表,如需转载,请注明页面地址。
code前端网


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