路由层级,父路由从哪来?
在Vue项目里用路由的时候,不少同学会碰到要获取父路由信息的需求——比如做面包屑导航得知道上一级路径,或者子路由要继承父路由的权限配置,那Vue Router到底怎么获取父路由呢?这篇文章从基础逻辑、具体方法到实际场景,把“父路由怎么拿、拿来有啥用、踩坑咋解决”这些问题掰碎了讲明白。
要理解“父路由”,得先搞懂Vue Router的**嵌套路由**逻辑,在路由配置里,父路由和子路由是通过「层级嵌套」关联的——父路由的配置对象里有个`children`数组,专门用来放子路由;父路由对应的组件里得有`举个简单的路由配置例子:
const routes = [
{
path: '/user', // 父路由的路径
name: 'User', // 父路由的名称
component: UserLayout, // 父路由对应的组件
children: [ // 子路由配置在这里
{
path: 'profile', // 子路由的路径(完整路径是 /user/profile)
name: 'UserProfile',
component: UserProfile
}
]
}
]
在这个配置里,/user是父路由,/user/profile是它的子路由,当用户访问/user/profile时,Vue Router会先渲染父路由的UserLayout组件,再通过UserLayout里的<router-view/>渲染子路由的UserProfile组件,这时候,UserProfile组件里的「父路由」,就是/user对应的路由对象。
最直接的方法:$route.parent属性
Vue Router给每个路由组件都提供了一个$route对象,用来保存当前路由的信息(比如路径、名称、参数、元信息等),而其中的parent属性,就是专门用来指向「父路由的路由对象」的(前提是当前路由是嵌套路由,也就是在父路由的children里配置的)。
基本用法:组件内访问$route.parent
在子路由对应的组件里,可以直接通过this.$route.parent拿到父路由的信息,比如在上面例子的UserProfile组件里:
export default {
mounted() {
const parentRoute = this.$route.parent;
console.log(parentRoute.path); // 输出:/user
console.log(parentRoute.name); // 输出:User
console.log(parentRoute.meta); // 输出父路由的meta配置(如果有的话)
}
}
这里要注意一个关键点:只有嵌套路由才有父路由,如果你的路由配置里,子路由没放在父路由的children数组里(比如只是路径上看着像父子,但配置是平级的),那this.$route.parent会是null。
实际场景:父路由信息能解决什么问题?
知道了怎么拿父路由,接下来得明白「拿父路由信息」在实际开发中能解决哪些痛点,下面举两个常见场景:
场景1:面包屑导航的自动生成
面包屑导航需要展示「从首页到当前页面的层级路径」,这时候父路由的信息就很关键,比如要实现「首页 > 用户中心 > 个人资料」这样的导航,父路由(/user)的名称和路径就是“用户中心”那一级。
代码示例(假设每个路由都配置了meta.title来存页面标题):
<template>
<div class="breadcrumb">
<!-- 首页 -->
<router-link :to="{ name: 'Home' }">{{ $t('home') }}</router-link>
<span>/</span>
<!-- 父路由 -->
<router-link
v-if="parentRoute"
:to="{ name: parentRoute.name }"
>{{ parentRoute.meta.title }}</router-link>
<span>/</span>
<!-- 当前路由 -->
<span>{{ $route.meta.title }}</span>
</div>
</template>
<script>
export default {
computed: {
parentRoute() {
return this.$route.parent; // 获取父路由对象
}
}
}
</script>
这样一来,只要路由配置正确嵌套,面包屑就能自动根据父路由和当前路由的信息生成,不用手动写死每一级导航。
场景2:权限控制的继承
很多项目里,父路由的页面需要登录才能访问,子路由页面也需要同样的权限,这时候可以把「是否需要登录」的配置放在父路由的meta里,子路由通过父路由的信息来复用这个配置,避免重复写权限逻辑。
父路由配置(简化版):
{
path: '/user',
name: 'User',
meta: {
requiresAuth: true // 父路由要求登录
},
children: [
{
path: 'profile',
name: 'UserProfile',
component: UserProfile
}
]
}
子路由组件里判断权限:
export default {
beforeRouteEnter(to, from, next) {
// 通过父路由的meta判断是否需要登录
const requiresAuth = to.parent.meta.requiresAuth;
if (requiresAuth && !isLogin()) {
next({ name: 'Login' }); // 没登录就跳登录页
} else {
next();
}
}
}
这种「继承父路由权限配置」的思路,能让代码更简洁,也减少了重复配置的维护成本。
容易踩的坑:parent拿不到怎么办?
不少同学按照方法写了代码,结果this.$route.parent是null,这时候要从「路由配置」和「组件结构」两个方向排查问题:
坑1:路由配置没真正“嵌套”
很多人会误以为「路径带/层级」就是嵌套路由,但Vue Router的嵌套路由必须通过children数组配置,比如下面这种「假嵌套」配置:
// 错误配置:子路由没放在children里
const routes = [
{
path: '/user',
name: 'User',
component: UserLayout
},
{
path: '/user/profile',
name: 'UserProfile',
component: UserProfile
}
]
在这个配置里,/user/profile和/user是平级路由(只是路径有重叠),所以UserProfile组件的$route.parent会是null,解决方法很简单:把/user/profile放到/user的children数组里。
坑2:父路由组件没加
父路由对应的组件(比如上面的UserLayout)必须包含<router-view/>,否则子路由组件不会被渲染,自然也没法和父路由建立关联。
错误的父组件示例:
<template>
<div>
<!-- 少了<router-view/>,子路由组件不会被渲染 -->
<h1>用户中心</h1>
</div>
</template>
正确的父组件应该这样写:
<template>
<div>
<h1>用户中心</h1>
<router-view/> <!-- 这里渲染子路由组件 -->
</div>
</template>
坑3:混淆$route和$router
Vue Router里,$route是「当前路由的信息对象」(包含path、name、parent等),而$router是「路由实例」(用来做跳转,比如$router.push),如果不小心写成this.$router.parent,肯定拿不到父路由信息——因为$router根本没有parent属性!
进阶:父路由元信息的传递与复用
除了路径、名称这些基础信息,父路由的meta(元信息)也很常用,很多时候,我们会在父路由的meta里配置一些「全局生效」的信息(比如页面标题、侧边栏菜单、权限标记),子路由可以通过$route.parent.meta直接复用这些配置。
例子:统一设置页面标题
假设所有用户相关的页面(父路由和子路由)都要在浏览器标签栏显示“用户中心 - XXX”,可以在父路由的meta里配置基础标题,子路由再补充自己的标题:
父路由配置:
{
path: '/user',
name: 'User',
meta: {
baseTitle: '用户中心' // 父路由的基础标题
},
children: [
{
path: 'profile',
name: 'UserProfile',
meta: {
subTitle: '个人资料' // 子路由的子标题
},
component: UserProfile
}
]
}
子路由组件里组合标题:
export default {
mounted() {
const parentMeta = this.$route.parent.meta;
document.title = `${parentMeta.baseTitle} - ${this.$route.meta.subTitle}`;
// 输出:用户中心 - 个人资料
}
}
例子:侧边栏菜单的自动激活
如果父路由对应侧边栏的一个大模块(用户中心”),子路由对应模块内的子菜单(个人资料”“订单管理”),可以通过父路由的meta来标记「当前激活的大模块」。
父路由配置:
{
path: '/user',
name: 'User',
meta: {
sidebarKey: 'user' // 标记属于“用户”模块
},
children: [
{
path: 'profile',
name: 'UserProfile',
component: UserProfile
}
]
}
侧边栏组件里根据父路由的sidebarKey激活菜单:
<template>
<div class="sidebar">
<ul>
<li :class="{ active: currentKey === 'home' }">首页</li>
<li :class="{ active: currentKey === 'user' }">用户中心</li>
</ul>
</div>
</template>
<script>
export default {
computed: {
currentKey() {
// 如果当前路由有父路由,用父路由的sidebarKey;否则用自己的
return this.$route.parent?.meta.sidebarKey || this.$route.meta.sidebarKey;
}
}
}
</script>
这样不管用户访问的是父路由(/user)还是子路由(/user/profile),侧边栏的“用户中心”都会自动激活,体验更连贯。
路由层级的延伸:多级嵌套下的父路由链
实际项目里,路由可能不止两级嵌套(爷爷路由 → 父路由 → 子路由」),这时候,$route.parent的父路由还有自己的parent,形成一条「父路由链」,我们可以利用这个特性,处理更复杂的场景(比如多级面包屑、多层权限继承)。
例子:多级面包屑的遍历
假设路由是三级嵌套:/home(爷爷)→ /home/user(父)→ /home/user/profile(子),要生成「首页 > 用户中心 > 个人资料」这样的三级面包屑,可以通过循环遍历parent链实现:
export default {
methods: {
getBreadcrumbList() {
const breadcrumb = [];
let currentRoute = this.$route; // 从当前路由开始
while (currentRoute) {
breadcrumb.unshift(currentRoute); // 往前插,保证顺序是从根到当前
currentRoute = currentRoute.parent; // 跳到父路由
}
return breadcrumb;
}
}
}
模板里渲染:
<template>
<div class="breadcrumb">
<span
v-for="(route, index) in getBreadcrumbList()"
:key="route.path"
>
<router-link v-if="index !== getBreadcrumbList().length - 1" :to="{ name: route.name }">
{{ route.meta.title }}
</router-link>
<span v-else>{{ route.meta.title }}</span>
<span v-if="index !== getBreadcrumbList().length - 1"> / </span>
</span>
</div>
</template>
这样不管路由嵌套多少层,面包屑都能自动生成,不用手动维护每一级的关联。
掌握父路由,让路由逻辑更丝滑
Vue Router里获取父路由的核心是$route.parent,但要真正用顺,得理解嵌套路由的配置规则(children数组 + <router-view/>),还要结合实际场景(面包屑、权限、页面配置)灵活运用。
记住这几个关键点:
- 只有嵌套路由才有父路由,平级路由的
parent是null; - 父路由信息(路径、名称、meta)都存在
$route.parent里,按需取用; - 遇到
parent拿不到的情况,先检查「路由配置是否嵌套」和「父组件是否有」。
把这些逻辑理顺后,不管是做导航、权限还是页面配置,都能更高效地复用父路由的信息,让项目的路由逻辑更简洁、更易维护~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网




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