Vue嵌套路由

在单页应用里,"页面"不再是整屏刷新,而是由路由驱动的组件树。当业务复杂到「用户中心 → 个人资料 / 收货地址 / 账号安全 / 好友列表」这种层级时,嵌套路由(Nested Routes)是唯一能把深度与可维护性同时保留下来的方案。

一、嵌套路由到底在解决什么问题

想象一个用户中心:

bash 复制代码
/user                 用户中心外壳(Layout)
├── /user/profile     个人资料
├── /user/address     收货地址
├── /user/security    账号安全
└── /user/friends     好友列表

如果写成平级路由,每切换一个子页面就要重新加载整个外壳(导航、侧边栏、用户信息),浪费、卡顿、状态丢失。

嵌套路由让外壳只挂载一次,子页面作为 <router-view> 的局部插槽渲染,完美复用外壳,并天然支持面包屑、标签页、权限控制。

二、一条代码看全貌

js 复制代码
// router/index.js
const routes = [
  {
    path: '/user',
    component: () => import('@/views/user/Layout.vue'), // 外壳
    children: [
      { path: '',           component: () => import('@/views/user/Profile.vue') },
      { path: 'address',    component: () => import('@/views/user/Address.vue') },
      { path: 'security',   component: () => import('@/views/user/Security.vue') },
      { path: 'friends',    component: () => import('@/views/user/Friends.vue') }
    ]
  }
]

要点:

  • 层级关系 = 文件系统:父路由的 component 是文件夹,children 是里面的文件。
  • 默认子路由 = 空字符串 '',访问 /user 时自动渲染 Profile
  • 路径写法 = 相对路径:address 会自动拼接成 /user/address,无需手写全量。

三、Layout 组件

vue 复制代码
<!-- views/user/Layout.vue -->
<template>
  <div class="user-center">
    <aside>
      <router-link to="/user">个人资料</router-link>
      <router-link to="/user/address">收货地址</router-link>
      <router-link to="/user/security">账号安全</router-link>
      <router-link to="/user/friends">好友列表</router-link>
    </aside>
    <main>
      <router-view />   <!-- 子路由插在这里 -->
    </main>
  </div>
</template>

子页面渲染时,Layout 组件不会重新创建,导航高亮、用户信息、WebSocket 连接全部保持。

四、动态路由 + 嵌套:URL 即状态

把用户 ID 塞进路径:

js 复制代码
{
  path: '/user/:id',
  component: () => import('@/views/user/Layout.vue'),
  props: true,              // 把 id 作为 prop 注入 Layout
  children: [
    { path: '',        component: () => import('@/views/user/Profile.vue'), props: true },
    { path: 'address', component: () => import('@/views/user/Address.vue'),  props: true }
  ]
}

访问 /user/42/address 时:

  • Layout 通过 props.id 拿到 42,去拉用户信息;
  • Address 通过 props.id 再去拉地址列表;
  • 切换子路由只改后半段,外壳复用,接口只增不重复。

五、项目实践

1.权限与面包屑

js 复制代码
{
  path: '/user',
  component: Layout,
  meta: { title: '用户中心', needAuth: true },
  children: [
    { path: '', meta: { title: '个人资料' } },
    { path: 'address', meta: { title: '收货地址' } }
  ]
}

全局后置钩子:

js 复制代码
router.afterEach(to => {
  document.title = to.matched
    .map(r => r.meta.title)
    .filter(Boolean)
    .join(' - ')
})

matched 数组从根到当前节点依次展开,天然就是面包屑数据源。

权限同理:在导航守卫里检查 to.matched.some(r => r.meta.needAuth),一次递归即可拿到所有层级要求。

2.代码分割

  • 父路由同步加载:外壳体积小,保证首屏骨架秒出;
  • 子路由全部懒加载:利用魔法注释给 chunk 命名,方便 CDN 缓存。
js 复制代码
component: () =>
  import(/* webpackChunkName: "user-security" */ '@/views/user/Security.vue')

六、常见问题

  • 空路径与斜杠:path: ''path: '/' 都匹配 /user,但后者会额外触发重定向,导致外壳重复渲染。
  • 深度监听失效:在 Layoutwatch $route 时,记得加 immediate: true,否则首次进入不触发。
  • 滚动位置丢失:给 <router-view>key="$route.fullPath" 可强制重新挂载,但会破坏缓存;更优解是在 activated 钩子里手动恢复 scrollTop。
相关推荐
胡gh几秒前
什么是瀑布流?用大白话给你讲明白!
前端·javascript·面试
C4程序员4 分钟前
北京JAVA基础面试30天打卡06
java·开发语言·面试
universe_016 分钟前
day22|学习前端ts语言
前端·笔记
teeeeeeemo9 分钟前
一些js数组去重的实现算法
开发语言·前端·javascript·笔记·算法
Zz_waiting.11 分钟前
Javaweb - 14.1 - 前端工程化
前端·es6
掘金安东尼13 分钟前
前端周刊第426期(2025年8月4日–8月10日)
前端·javascript·面试
Abadbeginning13 分钟前
FastSoyAdmin导出excel报错‘latin-1‘ codec can‘t encode characters in position 41-54
前端·javascript·后端
ZXT15 分钟前
WebAssembly
前端
卢叁15 分钟前
Flutter开发环境安装指南
前端·flutter
curdcv_po33 分钟前
Three.js,闲谈3D——智慧XX
前端