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。
相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万2 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A2 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋2 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
晨米酱2 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
卡布鲁2 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
honkun62 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
彧azz2 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试