一、vue-router子路由到底是什么?
刚接触vue-router的同学,经常会疑惑「子路由是啥?配置和使用时有啥要注意的?碰到不显示、传参失败这些问题咋解决?」今天就用问答形式把vue-router子路由的核心知识、实操方法、避坑技巧一次性讲明白,新手也能轻松看懂~
子路由是**路由的“嵌套结构”**——父路由对应的组件里得有个`打个比方:做后台管理系统时,肯定有个“整体布局组件”(比如叫Layout
),里面包含侧边栏、顶部导航栏,中间留一块区域放不同页面(比如用户列表、订单列表),这时候,“用户列表”“订单列表”这些路由就是Layout
的子路由,它们的组件会被塞进Layout
里的<router-view>
位置。
子路由的核心作用是实现页面嵌套布局,让代码结构像“俄罗斯套娃”一样一层包一层,既符合SPA(单页应用)的组件化思想,又能让用户切换子页面时,外层布局(比如侧边栏)保持不变,体验更流畅。
怎么给项目配置子路由?分步骤讲
配置子路由像“搭积木”,得先准备好带<router-view>
的父组件,再给路由规则加“子规则”,下面一步步拆:
步骤1:准备父路由组件
先写负责“外层布局”的父组件(比如叫Layout.vue
),里面必须包含<router-view>
(这是子路由组件的“挂载点”),举个简单结构:
<template> <div class="layout"> <aside>侧边栏</aside> <main> <!-- 子路由组件会渲染到这里 --> <router-view></router-view> </main> </div> </template>
步骤2:在路由配置里加children
数组
打开路由配置文件(比如router/index.js
),给父路由对象加children
属性(数组类型),每个数组元素是子路由规则,注意这些细节:
- 子路由的
path
不用加斜杠(比如父路由path
是/dashboard
,子路由path
写analysis
,完整路径就是/dashboard/analysis
;加斜杠会变成根路径下的路由,脱离父路由)。 - 每个子路由得配
component
(要渲染的组件),用懒加载(() => import('./views/xxx.vue')
)更高效。
举个完整配置例子:
import { createRouter, createWebHistory } from 'vue-router' import Layout from '@/views/Layout.vue' const routes = [ { path: '/dashboard', // 父路由路径 component: Layout, // 父路由组件 children: [ { path: 'analysis', // 子路由路径,完整路径/dashboard/analysis component: () => import('@/views/DashboardAnalysis.vue') // 子组件(懒加载) }, { path: 'workbench', component: () => import('@/views/DashboardWorkbench.vue') } ] } ] const router = createRouter({ history: createWebHistory(), routes }) export default router
步骤3:用<router-link>
或编程式导航跳转
配置好后,跳转子路由有两种方式:
- 声明式导航:用
<router-link>
标签,比如跳转到analysis
子路由:<router-link to="/dashboard/analysis">分析页</router-link>
- 编程式导航:在方法里用
this.$router.push('/dashboard/analysis')
(Vue2)或useRouter().push('/dashboard/analysis')
(Vue3)。
踩坑提醒:如果子路由没渲染,先检查父组件有没有<router-view>
,以及子路由的path
和父路由的path
是否“拼接”正确~
子路由有哪些实用场景?
子路由不止“嵌套”这么简单,实际项目里能解决很多布局和交互问题,举几个高频场景:
场景1:后台管理系统的“布局复用”
后台系统常见结构是「侧边栏+顶部栏+内容区」,把侧边栏和顶部栏放到Layout
组件里,内容区用<router-view>
,用户、订单、商品等模块作为子路由,切换时只有内容区刷新,侧边栏和顶部栏不动,既减少重复代码,又让用户操作更流畅。
场景2:页面内的Tab切换
比如商品详情页有「基本信息」「用户评价」「推荐商品」三个Tab,给每个Tab配个子路由,点击Tab时切换子路由,不仅能让路由记录当前Tab状态(刷新页面也能回到当前Tab),还能通过路由传参(比如商品ID)让每个Tab组件更独立。
场景3:多级导航的“层级嵌套”
像电商平台的分类页:一级分类(数码”)是父路由,二级分类(手机”)是子路由,三级分类(苹果手机”)是子路由的子路由(孙子路由),每层路由对应不同组件,用<router-view>
一层套一层,完美实现多层级页面结构。
子路由常见问题怎么解决?
配置和使用时,最容易碰到“子组件不显示”“传参失败”这些坑,下面逐个拆解解决方案:
问题1:子路由组件死活不显示?
先做这几步排查:
- 检查父路由组件里有没有
<router-view>
,没写这个标签,子组件根本没地方渲染! - 检查子路由的
path
是否正确,比如父路由path
是/dashboard
,子路由path
写成/dashboard/analysis
(多写了父路径),会导致路径不匹配。 - 检查路由配置语法,比如
children
数组是不是放在父路由对象里?有没有少写逗号、括号?(新手容易犯这种错) - 检查子组件是否正确导入,比如懒加载时路径写错导致404,或组件没
export default
导致“组件未定义”。
问题2:子路由怎么传参?三种方法任选
子路由和父路由传参逻辑和普通路由一致,但要注意“路径层级”,推荐这三种方法:
-
动态路由传参:子路由
path
写动态参数(比如path: 'detail/:id'
),跳转时用/dashboard/detail/123
,子组件通过this.$route.params.id
(Vue2)或useRoute().params.id
(Vue3)获取。 -
查询参数(query):跳转时带
?name=xxx
(比如<router-link to="/dashboard/detail?name=手机">
),子组件用this.$route.query.name
拿值,好处是参数可见,刷新页面参数不丢。 -
props传参(推荐解耦写法):在子路由配置里开
props: true
,子组件用props
接收,例子:// 路由配置 { path: 'detail/:id', component: ProductDetail, props: true } // 子组件ProductDetail.vue export default { props: ['id'], mounted() { console.log(this.id) // 直接用props,不用依赖$route,更解耦 } }
问题3:子路由的导航守卫咋用?
导航守卫能控制“能不能进入子路由”,常用这两种场景:
- 子路由独享守卫
beforeEnter
:写在子路由配置里,进入子路由前判断权限。{ path: 'analysis', component: DashboardAnalysis, beforeEnter: (to, from, next) => { if (localStorage.getItem('token')) { // 假设用token判断权限 next() // 有权限,进入子路由 } else { next('/login') // 没权限,跳登录页 } } }
- 父组件的
beforeRouteUpdate
:子路由切换但父组件被复用(比如动态路由参数变化)时,这个钩子会触发,比如父路由是/user/:id
,从/user/1
跳到/user/2
,父组件复用,这时可在beforeRouteUpdate
里更新数据:export default { beforeRouteUpdate(to, from, next) { this.fetchData(to.params.id) // 根据新的id重新请求数据 next() } }
问题4:子路由和动态路由有啥区别?
很多同学会混淆这两个概念,简单总结:
- 动态路由:核心是“路径带参数”(比如
/user/:id
),用来匹配不同ID的用户页面,重点在“参数匹配”。 - 子路由:核心是“嵌套结构”,用来实现页面的层级布局,重点在“组件嵌套”。
- 关系:动态路由可以是子路由的一部分,比如父路由是
/user
,子路由是/user/:id/profile
,这时子路由同时也是动态路由。
子路由进阶:多层嵌套与性能优化
项目复杂时,子路由可能要嵌套“孙子路由”,甚至做性能优化,掌握后能让项目更丝滑~
多层嵌套:子路由里再套子路由
做“三层嵌套”页面(A组件→B组件→C组件)时,配置要在子路由的children
里再放children
:
{ path: '/a', component: A, children: [ { path: 'b', component: B, children: [ { path: 'c', component: C } ] } ] }
这时,A组件里的<router-view>
渲染B组件,B组件里的<router-view>
渲染C组件。注意:每一层嵌套都得有<router-view>
,否则下一层组件没地方渲染!
性能优化:懒加载+keep-alive
子路由多的话,全塞进首屏加载会很慢,用懒加载(把component
写成() => import('xxx.vue')
)能让首屏只加载必要组件,其他子路由等需要时再加载,减少初始包体积。
用keep-alive
缓存子路由组件实例,避免重复渲染,在父组件的<router-view>
外层包keep-alive
:
<template> <div class="layout"> <aside>侧边栏</aside> <main> <keep-alive> <router-view></router-view> </keep-alive> </main> </div> </template>
但keep-alive
会缓存组件状态,若子组件需“每次进入都刷新数据”,得用activated
和deactivated
钩子:
export default { activated() { this.fetchData() // 每次激活组件(进入子路由)时请求数据 }, deactivated() { // 离开时的逻辑,比如清空定时器 } }
到这里,vue-router子路由的核心知识、配置方法、避坑技巧、进阶玩法就讲透啦~记住核心逻辑:子路由是嵌套结构,靠父组件的<router-view>
挂载,配置时用children
数组,使用时注意路径和传参细节,多在项目里实操几次,自然就熟练啦~如果还有其他问题,评论区随时喊我~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。