一、嵌套路由是干啥的?先看实际场景
做Vue项目时,不少同学碰到过这种情况:一个页面里得嵌套另一个页面,比如后台管理系统左边是侧边栏(固定的父页面),右边内容区要根据侧边栏选项切换不同子页面,这时候Vue Router的嵌套路由就是解决这类问题的关键,但嵌套路由到底是啥?咋配置?遇到问题咋处理?今天咱用大白话+实际例子,把这些事儿掰碎了讲清楚。
嵌套路由本质是「路由的层级管理」,让URL结构和页面组件结构一一对应,举个常见例子:比如做一个博客系统,有个/article路由对应文章列表页(父组件),列表页里点某篇文章,要跳转到/article/123(子组件,文章详情页),这时候/article是父路由,/article/:id是子路由,这种层级关系就需要嵌套路由来实现。
再比如后台管理系统,/admin对应侧边栏+顶部栏的布局(父组件),点击侧边栏的「用户管理」,右边显示/admin/users(子组件);点击「订单管理」,右边显示/admin/orders(另一个子组件),父组件的布局不变,只切换子组件,这就是嵌套路由的典型场景。
嵌套路由核心:父路由、子路由和<router-view>有啥关系?
要理解嵌套路由,得先搞懂<router-view>这个东西,它是Vue Router提供的「路由组件挂载点」—— 你配置的路由组件(比如ArticleList、ArticleDetail),会被渲染到<router-view>所在的位置。
嵌套路由的关键是「<router-view>的嵌套」:父路由对应的组件模板里,得放一个<router-view>,用来渲染子路由对应的组件,举个例子:
父组件ArticleList的模板长这样:
<template>
<div class="article-list">
<h2>文章列表</h2>
<ul>
<li v-for="article in articles" :key="article.id">
<router-link :to="'/article/' + article.id">{{ article.title }}</router-link>
</li>
</ul>
<router-view></router-view> <!-- 子组件(文章详情)会渲染到这里 -->
</div>
</template>
当用户点击文章链接,进入/article/123时,子路由对应的ArticleDetail组件,就会被渲染到父组件ArticleList里的<router-view>位置,这就是「嵌套」的核心逻辑:父组件用<router-view>承载子组件。
咋配置嵌套路由?分步骤教你写代码
配置嵌套路由分三步:定义路由规则(用children数组)、父组件加<router-view>、设置子路由导航,咱一步一步来。
路由规则里用children数组定义子路由
在router/index.js里,给父路由配置children数组,里面放子路由的规则。
import Vue from 'vue'
import VueRouter from 'vue-router'
import ArticleList from '../views/ArticleList.vue'
import ArticleDetail from '../views/ArticleDetail.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/article', // 父路由路径
component: ArticleList, // 父路由组件
children: [ // 子路由规则放在children里
{
path: ':id', // 子路由路径,注意:这里没加/,是相对父路由的路径
component: ArticleDetail // 子路由组件
}
]
}
]
const router = new VueRouter({
mode: 'history',
routes
})
export default router
这里要注意path: ':id'没加,因为加了会变成「绝对路径」,比如父路由是/article,子路由path写/detail,那访问路径是/detail,而不是/article/detail,所以子路由path用「相对路径」(不加),这样访问路径就是/article/123(父路径+子路径)。
父组件模板里加<router-view>
父组件(比如ArticleList)的模板必须包含<router-view>,否则子组件没地方渲染,页面会空白,像这样:
<template>
<div>
<h2>文章列表</h2>
<!-- 这里是文章列表的内容 -->
<router-view></router-view> <!-- 子组件(ArticleDetail)会渲染到这里 -->
</div>
</template>
子路由的导航咋写?用<router-link>或编程式导航
导航到子路由有两种方式:<router-link>组件或者编程式导航(this.$router.push)。
用<router-link>的话,可以写绝对路径或相对路径:
<!-- 绝对路径:/article/ + 文章id --> <router-link :to="'/article/' + article.id">查看文章</router-link> <!-- 相对路径:在父组件内时,to可以直接写子路径 --> <router-link :to="article.id">查看文章</router-link>
编程式导航同理:
// 绝对路径
this.$router.push('/article/' + article.id)
// 相对路径(在父组件内时)
this.$router.push(article.id)
相对路径更灵活,比如父路由路径变了(比如从/article改成/posts),子路由导航不用挨个改,所以推荐在父组件内用相对路径。
嵌套路由里的 tricky 问题咋解决?(默认路由、404、传参)
配置嵌套路由时,总会遇到一些细节问题:比如进入父路由时自动显示某个子页面、子路由找不到时显示404、父路由参数咋传给子组件,咱一个个解决。
默认子路由:进入父路由时自动渲染子组件
需求:访问/article时,自动显示「文章推荐」子组件,而不是空白,这时候给子路由配path: ''(空路径)。
路由规则改成这样:
children: [
{
path: '', // 空路径,匹配/article
component: ArticleRecommend // 默认子组件
},
{
path: ':id',
component: ArticleDetail
}
]
这样访问/article时,会渲染ArticleRecommend;访问/article/123时,渲染ArticleDetail。
子路由的404页面:匹配不到子路由时显示错误页
需求:父路由下的子路由如果不存在(比如用户输错路径/article/abc,但abc不是有效文章id),显示404,这时候用「通配符」匹配所有未定义的子路径。
路由规则里,把404路由放在children因为路由匹配是「从上到下」,匹配所有,放最后才不会覆盖其他子路由):
children: [
{ path: '', component: ArticleRecommend },
{ path: ':id', component: ArticleDetail },
{ path: '*', component: ArticleNotFound } // 404组件
]
这样访问/article/xxx(xxx不是有效id且没被其他子路由匹配)时,就会渲染ArticleNotFound。
嵌套路由的参数传递:父路由参数咋给子组件?
比如父路由是/article/:category(比如/article/frontend),子路由要拿到category参数,有两种方式:
子组件通过$route.params获取
子组件里直接用this.$route.params.category,但这种方式让子组件「紧耦合」$route,不利于组件复用和测试。
用props传递参数(推荐)
路由规则里给父路由和子路由开启props,把参数通过props传给组件。
{
path: '/article/:category',
component: ArticleList,
props: true, // 父组件通过props接收category
children: [
{
path: ':id',
component: ArticleDetail,
props: (route) => ({
category: route.params.category, // 从父路由参数拿category
id: route.params.id
})
}
]
}
父组件ArticleList的props接收category:
export default {
props: ['category'],
mounted() {
console.log('当前分类:', this.category) // 比如frontend
}
}
子组件ArticleDetail的props接收category和id:
export default {
props: ['category', 'id'],
mounted() {
console.log('当前分类:', this.category, '文章id:', this.id)
}
}
这样组件不依赖$route,更灵活,也方便写单元测试。
实战:做个后台管理页面的嵌套路由
光说不练假把式,咱做个简单的后台管理页面,包含「用户管理」和「订单管理」两个模块,每个模块下有子页面。
规划路由结构
- 父路由:
/admin,对应侧边栏+顶部栏布局(组件AdminLayout) - 子路由1:
/admin/users,对应用户列表页(组件UserList) - 子路由2:
/admin/users/add,对应添加用户页(组件UserAdd,是users的子路由) - 子路由3:
/admin/orders,对应订单列表页(组件OrderList)
编写路由规则(router/index.js)
import Vue from 'vue'
import VueRouter from 'vue-router'
import AdminLayout from '../views/AdminLayout.vue'
import UserList from '../views/UserList.vue'
import UserAdd from '../views/UserAdd.vue'
import OrderList from '../views/OrderList.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/admin',
component: AdminLayout,
children: [
{
path: '', // 默认子路由:访问/admin时重定向到users
redirect: 'users'
},
{
path: 'users', // 相对路径,完整路径是/admin/users
component: UserList,
children: [ // users的子路由
{
path: 'add', // 完整路径/admin/users/add
component: UserAdd
}
]
},
{
path: 'orders',
component: OrderList
}
]
}
]
const router = new VueRouter({
mode: 'history',
routes
})
export default router
编写父组件模板(AdminLayout.vue)
AdminLayout是/admin的组件,包含侧边栏和<router-view>(渲染users或orders):
<template>
<div class="admin-layout">
<aside>
<h3>后台管理</h3>
<nav>
<router-link to="users">用户管理</router-link>
<router-link to="orders">订单管理</router-link>
</nav>
</aside>
<main>
<router-view></router-view> <!-- 渲染users或orders组件 -->
</main>
</div>
</template>
<script>
export default {
name: 'AdminLayout'
}
</script>
编写UserList组件(包含子路由add的<router-view>)
UserList是/admin/users的组件,里面要渲染/admin/users/add的子组件,所以模板里加<router-view>:
<template>
<div class="user-list">
<h2>用户列表</h2>
<button @click="goToAdd">添加用户</button>
<router-view></router-view> <!-- 渲染user-add组件 -->
</div>
</template>
<script>
export default {
name: 'UserList',
methods: {
goToAdd() {
// 编程式导航到子路由add
this.$router.push('add') // 相对路径,完整路径/admin/users/add
}
}
}
</script>
测试导航
- 访问
/admin:会自动重定向到/admin/users,main区域渲染UserList; - 点击「添加用户」按钮:路径变成
/admin/users/add,UserList里的<router-view>渲染UserAdd组件; - 点击侧边栏「订单管理」:路径变成
/admin/orders,main区域渲染OrderList。
通过这个实战案例,能直观感受到嵌套路由如何让页面结构和URL对应,以及多层嵌套(AdminLayout → UserList → UserAdd)的配置逻辑。
嵌套路由常见坑有哪些?避坑指南
新手配置嵌套路由时,很容易掉坑里,总结几个高频问题:
子路由path加了,导致路径错误
错误写法:子路由path写/child,父路由path是/parent,结果访问/child才能看到子组件,而不是/parent/child。
解决:子路由path不要加,用相对路径,比如父路由/parent,子路由path写child,访问路径就是/parent/child。
父组件没加<router-view>,子组件没地方渲染
症状:配置了子路由,但页面空白,控制台也没报错。
解决:检查父组件模板,必须包含<router-view>,子组件才会被渲染到那里。
路由匹配顺序搞反,导致子路由不生效
错误写法:把通配符放在子路由前面,
children: [
{ path: '*', component: NotFound },
{ path: 'child', component: Child }
]
结果访问/parent/child时,匹配到,渲染NotFound,而不是Child。
解决:路由匹配是「从上到下」,所以这类通配符路由要放在children数组最后,让具体路由先匹配。
默认子路由的path配置错误
错误写法:默认子路由path写,导致访问/parent时,匹配不到默认子路由。
解决:默认子路由path写(空字符串),这样访问/parent时才会匹配。
子组件获取父路由参数失败
症状:父路由有动态参数(比如/parent/:id),子组件用this.$route.params.id拿不到值。
原因:子路由的path没包含参数,或者参数传递方式不对。
解决:如果子路由需要父路由参数,要么在子路由path里包含参数(比如path: 'child/:id'),要么用props传递(前面讲的「方式二」)。
嵌套路由和其他技术咋结合?(Vuex、组件通信)
实际项目中,嵌套路由的不同层级组件可能需要共享数据,这时候可以结合Vuex或组件通信方式(如provide/inject)。
用Vuex共享状态
比如父组件和子组件都需要用户信息,把用户信息存在Vuex的store里:
// store/index.js
export default new Vuex.Store({
state: {
user: { name: '小明', role: 'editor' }
},
getters: {
getUser: state => state.user
}
})
父组件和子组件都可以通过this.$store.getters.getUser获取用户信息,不用关心组件层级。
用provide/inject跨层级传值
如果不想用Vuex,也可以用Vue的provide/inject特性,父组件用provide提供数据,子组件用inject接收。
父组件(如AdminLayout):
export default {
provide() {
return {
theme: this.theme // 假设theme是父组件的数据源
}
},
data() {
return {
theme: 'dark'
}
}
}
子组件(如UserList或UserAdd):
export default {
inject: ['theme'],
mounted() {
console.log('当前主题:', this.theme) // dark
}
}
这种方式适合「父组件到深层子组件」的跨层级通信,比props逐层传递更方便。
学会嵌套路由有啥用?总结价值
掌握嵌套路由,能解决「页面层级结构和
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网


