一、嵌套路由到底是个啥?
p>不少刚接触 Vue 路由的同学,一碰到嵌套路由就犯懵——明明配置了路由,子页面就是不显示;或者不知道啥场景该用嵌套,今天咱们就把 vue - router nested routes(嵌套路由)拆碎了讲,从“是啥”“为啥用”到“咋配置”“实战咋玩”,再到避坑,一次搞懂!
简单说,嵌套路由就是让路由组件像“俄罗斯套娃”一样分层嵌套,比如逛电商网站时,“商品”是个父页面,点进去后“商品列表”“商品分类”“促销活动”是子页面;这些子页面切换时,不需要整个页面刷新,只在父页面的特定区域更新——这个区域就是父组件里的<router - view>
,专门用来承载子路由对应的组件。
举个生活里的例子:手机“设置”APP 里,点进“网络设置”(父路由)后,里面还有“Wi - Fi”“移动数据”“热点”这些子选项(子路由),点不同子选项时,“网络设置”页面的主体内容变了,但顶部标题、侧边栏这类公共部分不变,这就是嵌套路由的典型场景。
为啥非得用嵌套路由?不能平级路由凑合吗?
要是不用嵌套,所有路由都平级配置,页面结构得重复写,还拿“设置”举例:每个子页面(Wi - Fi、移动数据)都得单独写顶部标题、侧边栏的 HTML 和逻辑,代码冗余到爆炸!而嵌套路由能实现 “结构复用 + 逻辑分层”:父组件负责公共布局(比如导航栏、侧边栏),子组件只处理自身独有的内容,后续维护起来轻松太多。
举个代码反例感受下:假设不用嵌套,每个子页面都复制父页面的导航栏代码,哪天产品经理说“导航栏加个夜间模式按钮”,所有子页面都得改一遍——这就是“牵一发动全身”,用嵌套的话,父组件改一次,所有子组件自动继承新结构,效率直接拉满!
手把手配置嵌套路由:就这三步!
下面用“博客系统首页拆分成新闻、消息两个子页面”的例子,带大家走一遍配置流程。
步骤 1:规划路由结构(先想清楚层级)
假设博客系统路由层级是这样:
- 一级路由:Home(首页)、Article(文章)、About(
- Home 页面里又分两个子页面:HomeNews(首页新闻)、HomeMessage(首页消息)
Home 是父路由,HomeNews 和 HomeMessage 是子路由。
步骤 2:在 router/index.js 里配置 children 属性
路由规则里,父路由通过 children
数组嵌套子路由,代码示例:
import Vue from 'vue' import Router from 'vue - router' import Home from '@/components/Home' import HomeNews from '@/components/HomeNews' import HomeMessage from '@/components/HomeMessage' Vue.use(Router) export default new Router({ routes: [ { path: '/home', // 父路由路径 component: Home, // 父路由对应的组件 // 关键:用 children 数组配置子路由 children: [ { // 子路由路径不加 / !会自动拼接父路由 path(/home + news → /home/news) path: 'news', component: HomeNews }, { path: 'message', component: HomeMessage }, // 可选:默认子路由(访问 /home 时自动跳转到 news) { path: '', // 空路径表示父路由的默认子路由 redirect: 'news' } ] } ] })
解释:children
是个数组,每个对象对应一条子路由规则。path
是相对于父路由的路径(不用写 ,否则会变成根路径),component
是子组件。
步骤 3:在父组件(Home.vue)里放 <router - view>
父组件的模板中,必须有 <router - view>
来承载子路由组件,示例:
<template> <div class="home"> <!-- 父组件的公共部分(比如导航栏) --> <div class="nav"> <router - link to="news">新闻</router - link> <router - link to="message">消息</router - link> </div> <!-- 关键:子路由组件会渲染到这个 <router - view> 里 --> <router - view></router - view> </div> </template> <script> export default { name: 'Home' } </script>
解释:父组件里的 <router - view>
是子路由组件的“容器”,访问 /home/news
时,HomeNews 组件会渲染到这里;访问 /home/message
时,HomeMessage 会渲染过来,父组件里的 <router - link>
可以直接用相对路径(to="news"
),因为会自动基于父路由的 path
拼接。
实战:用嵌套路由做后台管理系统布局
假设要做一个后台,左侧是菜单栏(父路由:Dashboard),右侧主体根据菜单切换子页面(用户管理、订单管理、商品管理),咱们一步步实现~
路由配置(router/index.js)
import Dashboard from '@/views/Dashboard' import UserManage from '@/views/UserManage' import OrderManage from '@/views/OrderManage' import ProductManage from '@/views/ProductManage' export default new Router({ routes: [ { path: '/dashboard', component: Dashboard, children: [ { path: 'user', component: UserManage }, // 子路由:用户管理 { path: 'order', component: OrderManage }, // 子路由:订单管理 { path: 'product', component: ProductManage }, // 子路由:商品管理 { path: '', redirect: 'user' } // 默认子路由:访问 /dashboard 时自动跳转到用户管理 ] } ] })
父组件 Dashboard.vue 的结构
<template> <div class="dashboard"> <!-- 左侧菜单(公共部分) --> <aside class="sidebar"> <ul> <li><router - link to="user">用户管理</router - link></li> <li><router - link to="order">订单管理</router - link></li> <li><router - link to="product">商品管理</router - link></li> </ul> </aside> <!-- 右侧主体,子组件渲染区 --> <main class="main - content"> <router - view></router - view> </main> </div> </template> <style scoped> .dashboard { display: flex; } .sidebar { width: 200px; background: #f5f5f5; } .main - content { flex: 1; padding: 20px; } </style>
子组件示例(UserManage.vue)
子组件只需要关注自身内容,不用重复写左侧菜单:
<template> <div> <h2>用户管理页面</h2> <p>这里可以做用户列表、新增、删除...</p> </div> </template>
这样设计后,访问 /dashboard/user
时,左侧菜单 + 右侧用户管理内容会渲染;访问 /dashboard/order
时,右侧自动切换成订单管理——公共的左侧菜单只在 Dashboard 组件里写了一次,复用性直接拉满!
嵌套路由 + 动态路由:更灵活的页面组合
再举个电商场景的例子:“商品”模块需要列表页嵌套详情页,且详情页要根据商品 ID 动态显示内容。
路由配置
{ path: '/product', component: ProductList, // 商品列表(父组件) children: [ { path: ':id', // 动态参数 id(对应不同商品) component: ProductDetail // 商品详情(子组件) } ] }
父组件 ProductList.vue 的结构
<template> <div class="product - list"> <!-- 商品列表 --> <ul> <li v - for="item in products" :key="item.id"> <router - link :to="`${item.id}`">{{ item.name }}</router - link> </li> </ul> <!-- 商品详情的容器 --> <router - view></router - view> </div> </template> <script> export default { data() { return { products: [ { id: 1, name: '手机' }, { id: 2, name: '电脑' } ] } } } </script>
子组件 ProductDetail.vue 获取参数
<template> <div class="product - detail"> <h2>商品 ID:{{ $route.params.id }}</h2> <p>这里显示对应商品的详情...</p> </div> </template>
这种设计的好处很明显:用户在商品列表页点击某个商品,详情页直接在列表页的指定区域渲染,不用跳转到全新页面,体验更流畅,还减少了页面加载次数。
嵌套路由常见坑 & 避坑指南
嵌套路由好用,但刚上手容易踩坑,下面总结几个高频问题和解决方法~
坑 1:子路由死活不显示?先查这三点!
- 父路由配置里有没有写
children
数组?(别漏了这个关键配置!) - 父组件模板里有没有放
<router - view>
?(子组件没地方渲染,自然不显示) - 子路由的
path
有没有加 ?(加了的话,路径会变成根路径,比如父路由是/home
,子路由path
写成news
是对的,写成/home/news
反而错了,会变成//home/news
这种无效路径)
坑 2:路由跳转后,父组件数据没更新?
Vue 为了性能优化,当子路由切换但父路由不变时,父组件不会重新渲染,如果需要在子路由切换时更新父组件数据,可以用 watch
监听 $route
:
watch: { '$route'(to, from) { // 路由变化时执行逻辑,比如重置数据、清除定时器 this.clearTimer() } }
坑 3:嵌套路由里的样式冲突?
父组件用了 <style scoped>
,子组件样式却被影响?scoped
是通过给元素加唯一属性实现作用域的,子组件根元素会继承父组件属性,如果子组件想完全脱离父组件样式,要么不用 scoped
(但要注意命名规范),要么用深度选择器(>>>
或 ::v - deep
),比如父组件要修改子组件里的 .class
:
<style scoped> .parent >>> .child - class { color: red; } </style>
坑 4:嵌套多层路由,路径太长咋管理?
如果有三级嵌套(/a/b/c
),路由配置里 children
套 children
会让代码很乱,可以把每个层级的路由拆成单独文件,a
路由的配置放在 a.js
,b
路由的配置放在 b.js
,用 children: require('./b.js').default
这种方式引入,让代码结构更清晰。
嵌套路由的进阶玩法:结合路由守卫
路由守卫能控制页面权限、处理数据加载,在嵌套路由中,父路由和子路由的守卫会按顺序执行(父路由守卫 → 子路由守卫)。
举个权限控制的例子:只有管理员能进 Dashboard 的子路由,在父路由的 beforeEnter
里判断:
{ path: '/dashboard', component: Dashboard, // 父路由守卫:进入前判断权限 beforeEnter: (to, from, next) => { const isAdmin = localStorage.getItem('role') === 'admin' if (isAdmin) { next() // 有权限,继续 } else { next('/login') // 没权限,跳登录 } }, children: [...] }
子路由也能单独加守卫,UserManage 需要“超级管理员”权限:
export default { name: 'UserManage', // 子路由守卫:进入前判断更细的权限 beforeRouteEnter(to, from, next) { const isSuperAdmin = localStorage.getItem('role') === 'superAdmin' if (isSuperAdmin) { next() } else { next(false) // 阻止进入 } } }
这种“嵌套路由 + 守卫”的组合,能实现多层级权限控制,让页面访问更安全。
嵌套路由的核心价值
嵌套路由本质是 “布局复用 + 逻辑分层” 的工具:把页面拆成“公共容器 + 可变内容”,用 <router - view>
当容器,children
配规则,让复杂页面的维护成本呈指数级下降,从基础配置到实战布局,再到避坑和进阶,掌握这些后,不管是做后台管理系统、电商页面还是复杂表单页,嵌套路由都能帮你把结构理得明明白白~
(全文完,约 2200 字)
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。