Vue Router的sub routes该怎么理解和使用?
做前端项目时,你有没有遇到过这样的场景?比如后台管理系统里,点击左侧菜单后,右侧内容区要切换不同页面,但整个页面的头部、侧边栏又得保持不变,这时候 Vue Router 的 sub routes(子路由)就能帮上大忙,可子路由到底是什么?怎么配置?实战中要注意啥?今天咱们就把这些问题掰碎了聊聊。
sub routes 到底是什么?
简单说,sub routes 是嵌套在「父路由」里的路由规则,对应到页面结构上,就是一个页面里嵌套另一个(或多个)可切换的子页面。
举个直观的例子:假设做一个博客系统,有个「文章管理」页面,点击进入后,左侧是文章分类导航,右侧要根据点击的分类,显示「已发布文章列表」「草稿箱」「回收站」这几个不同的子页面,这时候,「文章管理」就是父路由,它下面的「已发布」「草稿箱」这些就是子路由,父路由对应的组件负责布局(比如左侧导航栏),子路由对应的组件负责填充右侧的具体内容。
从代码层面看,父路由的配置里会有一个 children
数组,里面装着所有子路由的规则;父路由对应的 Vue 组件里,得有 <router - view>
标签,用来渲染子路由对应的组件——这就像给子路由留了个“占位符”,子路由组件会替换这个占位符的内容。
为什么项目里需要用 sub routes?
很多同学会疑惑:直接用普通路由切换页面不行吗?为啥非得搞嵌套?这得从实际开发的场景和好处说起。
解决页面结构嵌套的需求
后台管理系统是最典型的场景,比如常见的“顶部导航 + 左侧菜单 + 右侧内容区”布局,右侧内容区需要根据左侧菜单切换不同页面,但顶部和左侧是固定不变的,这时候,把“顶部 + 左侧”所在的页面作为父路由,右侧内容区用子路由来切换,就能完美实现这种嵌套结构,要是不用子路由,每次切换页面都得重新渲染整个页面(包括顶部和左侧),不仅体验差,代码重复度也高。
让代码拆分和复用更合理
父路由组件可以专门负责“布局”逻辑(比如处理侧边栏的展开收起、权限控制),子路由组件只需要关注“内容展示”,这样分工明确,代码复用性更强,比如多个子路由可能都需要父路由里的用户信息、权限判断逻辑,父组件处理后,子组件直接用就行,不用重复写。
路由逻辑分层更清晰
子路由天然继承父路由的部分特性,比如父路由需要登录后才能访问,那子路由也会自动要求登录(除非单独配置权限),把相关功能的路由聚合在父路由下,路由表的结构会更清晰,比如电商系统里,“商品管理”作为父路由,下面的“商品列表”“新增商品”“编辑商品”作为子路由,看路由配置就能明白功能模块的层级关系,维护起来更方便。
怎么配置 Vue Router 的 sub routes?
配置子路由的核心是「父路由里加 children 数组 + 父组件里放 <router - view>」,下面一步步拆解。
准备父路由组件
先写一个负责布局的父组件,DashboardLayout.vue
,里面得包含 <router - view>
来渲染子路由,示例代码:
注意:<router - link>
的 to
属性值,是相对于父路由的路径(后面讲路径配置时会详细说)。
配置路由规则里的 children
在 Vue Router 的路由数组中,给父路由对象加 children
数组,每个子路由对象包含 path
、component
等属性,示例路由配置:
const routes = [ { path: '/dashboard', // 父路由的路径 component: DashboardLayout, // 父路由对应的组件 children: [ { path: '', // 默认子路由,访问 /dashboard 时渲染这个 name: 'DashboardHome', component: DashboardHome }, { path: 'overview', // 子路由路径,完整路径是 /dashboard/overview component: Overview }, { path: 'analytics', // 完整路径 /dashboard/analytics component: Analytics } ] } ]
const router = createRouter({ history: createWebHistory(), routes })
export default router
<p>这里要注意几个关键点:</p>
<ul>
<li><strong>子路由的 path 不带 /</strong>:比如子路由写 <code>path: 'overview'</code>,那么完整路径是父路由的 <code>path</code>(/dashboard) + 子路由的 <code>path</code>(overview),即 <code>/dashboard/overview</code>,如果子路由写 <code>path: '/overview'</code>,完整路径会变成 <code>/overview</code>,就脱离父路由了,这是常见错误!</li>
<li><strong>默认子路由</strong>:当子路由的 <code>path</code> 为空字符串时,访问父路由的路径(如 /dashboard)时,会默认渲染这个子路由对应的组件(上面例子里的 DashboardHome)。</li>
<li><strong>父组件必须有 <router - view></strong>:如果父组件里没写 <code><router - view></code>,子路由组件没地方渲染,页面会一片空白,这也是新手常踩的坑。</li>
</ul>
## 四、实战中怎么结合组件结构用 sub routes?
<p>光看配置还不够,得结合真实项目结构理解,咱们以“后台管理系统的仪表盘模块”为例,完整走一遍流程。</p>
### 1. 规划项目文件结构
<p>假设项目的组件和视图结构如下:</p>
src/ ├── components/ │ └── layouts/ │ └── DashboardLayout.vue // 父路由组件(负责布局) ├── views/ │ └── dashboard/ │ ├── Home.vue // 仪表盘默认子页面 │ ├── Overview.vue // 概览子页面 │ └── Analytics.vue // 分析子页面 └── router/ └── index.js // 路由配置文件
### 2. 写父组件(DashboardLayout.vue)的布局逻辑
<p>父组件要包含侧边栏导航和 <code><router - view></code>,示例:</p>
```html
<template>
<div class="dashboard-layout">
<aside class="sidebar">
<h2>仪表盘</h2>
<nav>
<router - link to="">首页</router - link>
<router - link to="overview">概览</router - link>
<router - link to="analytics">分析</router - link>
</nav>
</aside>
<main class="content">
<router - view></router - view>
</main>
</div>
</template>
<script setup>
// 可以在这里处理侧边栏的展开/收起、权限判断等逻辑
import { onMounted } from 'vue'
onMounted(() => {
console.log('父组件加载,子路由还没渲染')
})
</script>
<style scoped>
.dashboard-layout {
display: flex;
}
.sidebar {
width: 200px;
background: #f5f7fa;
padding: 20px;
}
.content {
flex: 1;
padding: 20px;
}
</style>
写子组件(以 Overview.vue 为例)
子组件只需要关注自己的内容展示,
```html概览页面
这里展示系统的关键数据概览...
测试路由跳转
启动项目后,访问 /dashboard
,会看到侧边栏和默认子组件(Home.vue)的内容;点击“概览”的 router - link
,地址栏变成 /dashboard/overview
区切换为 Overview.vue 的内容——这就说明子路由配置成功了。
还可以给子路由加动态参数,比如商品编辑页面:
```javascript // 路由配置里加动态子路由 children: [ { path: 'edit/:id', // 动态参数 id component: ProductEdit } ]// ProductEdit 组件里获取参数 import { useRoute } from 'vue - router' const route = useRoute() const productId = route.params.id // 拿到路由参数
<p>这种动态子路由在“编辑详情”类场景中特别常用,父组件负责列表和布局,子路由负责具体的编辑页面,参数通过路由传递,逻辑更清晰。</p>
## 五、sub routes 容易踩的坑有哪些?
<p>子路由配置看起来简单,但实际开发中稍不注意就会出问题,总结几个高频“踩坑点”,帮你避坑。</p>
### 1. 父组件忘记加 <router - view>
<p><strong>现象</strong>:访问子路由时,父组件的布局能显示,但子组件内容空白。<br>
<strong>原因</strong>:子路由组件需要渲染到父组件的 <code><router - view></code> 里,如果父组件没写这个标签,子组件没地方渲染。<br>
<strong>解决</strong>:检查父组件模板,确保有 <code><router - view></router - view></code> 标签。</p>
### 2. 子路由 path 多写了 /
<p><strong>现象</strong>:点击子路由的 <code>router - link</code> 后,地址栏路径不对,页面404。<br>
<strong>原因</strong>:子路由的 <code>path</code> 开头加了 <code>/</code>,导致路径变成绝对路径,脱离父路由,比如父路由是 <code>/dashboard</code>,子路由写 <code>path: '/overview'</code>,完整路径会变成 <code>/overview</code>,而不是 <code>/dashboard/overview</code>。<br>
<strong>解决</strong>:子路由的 <code>path</code> 不要以 <code>/</code> 开头,保持相对路径。</p>
### 3. 默认子路由的导航链接问题
<p><strong>现象</strong>:访问父路由(如 <code>/dashboard</code>)时,默认子路由组件能渲染,但 <code>router - link</code> 的“首页”链接样式没激活(active - class 不生效)。<br>
<strong>原因</strong>:默认子路由的 <code>path</code> 是空字符串,<code>router - link</code> 的 <code>to</code> 属性写 <code>to=""</code> 时,匹配的是父路由路径,而默认子路由的 <code>path</code> 是空,所以需要给默认子路由加 <code>name</code>,<code>router - link</code> 用 <code>to="{ name: 'DashboardHome' }"</code> 来匹配。<br>
<strong>解决</strong>:给默认子路由配置 <code>name</code>,并在 <code>router - link</code> 中用命名路由跳转,示例:</p>
```javascript
// 路由配置
children: [
{
path: '',
name: 'DashboardHome', // 加 name
component: DashboardHome
}
]
// 父组件的 router - link
<router - link :to="{ name: 'DashboardHome' }">首页</router - link>
路由嵌套层级过深
现象:路由表变得臃肿,页面跳转逻辑复杂,维护困难。
原因:为了实现复杂布局,过度使用子路由嵌套(比如嵌套三层以上)。
解决:合理规划路由结构,把没必要嵌套的路由拆分成平级路由,或用命名视图替代深层嵌套,比如页面有多个并行区域(如头部、侧边、内容),用命名视图更合适,不用嵌套子路由。
子路由守卫和父路由守卫的执行顺序
现象:在子路由里用 beforeEnter
守卫,或在父组件里用 beforeRouteUpdate
,发现逻辑执行顺序和预期不一致。
原因:Vue Router 的导航守卫有固定的执行顺序(比如父路由的 beforeEnter
先于子路由的 beforeEnter
执行,子路由的 beforeRouteEnter
在组件创建前执行等),没理解清楚容易出错。
解决:查阅 Vue Router 官方文档,明确守卫的执行顺序,必要时通过 console.log
打印日志调试。
sub routes 和动态路由、命名视图有什么区别?
学子路由时,很容易和动态路由、命名视图搞混,得明确它们的区别。
和动态路由的区别
动态路由的核心是「路由参数」,/user/:id
,同一个组件(User.vue)根据不同的 id
显示不同用户的信息,组件会复用(不会销毁重建),而子路由的核心是「结构嵌套」,父组件负责布局,子组件负责不同内容的切换,组件是不同的。
举例子:动态路由适合“用户详情”“商品详情”这类场景(同一个页面模板,数据不同);子路由适合“仪表盘 - 概览/分析”这类嵌套布局场景(不同页面模板,结构嵌套)。
和命名视图的区别
命名视图是给 <router - view>
加 name
属性,一个页面里可以有多个 <router - view name="xxx">
,分别渲染不同的组件,比如一个页面要同时渲染「头部组件」「侧边栏组件」「主体组件」,这三个组件通过命名视图并行渲染。
而子路由是「嵌套渲染」——父组件里的 <router - view>
渲染子组件,子组件里还能再嵌套 <router - view>
渲染孙子路由,是层级关系。
举例子:命名视图适合“多区域并行渲染”(如门户首页的头部、轮播、推荐区);子路由适合“单区域嵌套渲染”(如后台管理系统的内容区嵌套子页面)。
在 Vue3 和 Vue2 中 sub routes 的使用有变化吗?
Vue2 和 Vue3 都支持子路由,但由于生态和 API 的变化,使用时也有一些细节差异。
路由配置方式
Vue2 中,路由通过 VueRouter
构造函数创建,示例:
const router = new Router({ routes: [ { path: '/dashboard', component
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。