Skip to content

嵌套路由 (Nested Routes)

1. 核心问题:为何需要嵌套路由?

在开发复杂应用时,常常会遇到一些页面共享相同的 UI 结构。例如,“用户中心”页面,无论你查看的是“个人资料”、“地址管理”还是“安全设置”,左侧的菜单栏总是固定不变的,只有右侧的内容区域在切换。

  • 传统方式的弊端:如果为“资料”、“地址”、“安全”分别创建三个独立的完整页面,那么共通的左侧菜单栏部分就需要被复制三遍,造成代码冗余和维护困难。
  • 嵌套路由的解决方案:将“用户中心”看作一个父级路由,其公共部分(如侧边栏)作为一个布局组件。具体变化的内容区域则作为子路由,动态渲染到布局组件中预留的占位符内。

2. 基础路由回顾

在理解嵌套路由前,我们先快速回顾一下基础的路由工作模式。

组件结构 (App.vue)

根组件 App.vue 通常包含全局导航链接 (<RouterLink>) 和一个路由出口 (<RouterView>)。

vue
<div id="app">
  <nav>
    <RouterLink to="/">首页</RouterLink>
    <RouterLink to="/about">关于我们</RouterLink>
    <RouterLink to="/user">用户中心</RouterLink>
  </nav>

  <RouterView />
</div>
  • <RouterLink>:生成导航链接,to 属性指定目标路径。
  • <RouterView>:一个占位符,路由匹配到的组件将会被渲染到这里。

路由配置 (router/index.js)

路由配置文件定义了路径 path 和组件 component 之间的映射关系。

javascript
// router/index.js
import Home from '@/views/Home.vue';
import About from '@/views/About.vue';

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/about',
    name: 'about',
    // 路由懒加载
    component: () => import('@/views/About.vue')
  }
  // ... 用户中心的路由配置将在这里展开
];

当 URL 变化时,路由器会查找匹配的 path,并将对应的 component 渲染到 <RouterView> 中。


3. 嵌套路由的实现

现在,我们来解决“用户中心”的问题。

步骤 1: 创建布局组件 (Layout Component)

首先,为“用户中心”创建一个布局组件 UserLayout.vue。这个组件包含了共享的 UI(左侧菜单)和它自己的 <RouterView> 用于显示子页面。

vue
<div class="user-center">
  <aside class="sidebar">
    <RouterLink to="/user">用户资料</RouterLink>
    <RouterLink to="/user/address">地址管理</RouterLink>
    <RouterLink to="/user/security">安全设置</RouterLink>
  </aside>

  <main class="content">
    <RouterView />
  </main>
</div>

步骤 2: 配置嵌套路由

在路由配置文件中,我们通过 children 属性来定义嵌套关系。

javascript
// router/index.js

const routes = [
  // ... 其他路由(首页、关于)
  {
    // 1. 父路由路径
    path: '/user',
    
    // 2. 父路由渲染的组件,即布局组件
    component: () => import('@/views/user/Layout.vue'),
    
    // 3. 'children' 属性定义嵌套的子路由
    //    当匹配到 /user 时,下面的组件会被渲染到 UserLayout.vue 的 <RouterView> 中
    children: [
      {
        // path 为空字符串,表示这是 /user 路径下的默认子路由
        // 当访问 /user 时,会匹配到此项
        path: '', 
        component: () => import('@/views/user/Profile.vue')
      },
      {
        // 子路由的 path 不以 '/' 开头。它会自动拼接在父路径之后
        // 完整访问路径: /user/address
        path: 'address',
        component: () => import('@/views/user/Address.vue')
      },
      {
        // 完整访问路径: /user/security
        path: 'security',
        component: () => import('@/views/user/Security.vue')
      }
    ]
  }
];

关键点

  • component: 父路由的 component 指向布局组件 (UserLayout.vue)。
  • children: 一个数组,包含了所有子路由的配置对象。
  • 子路由 path:
    • 空字符串 '': 定义了父路径的默认子路由。当用户访问 /user 时,Profile.vue 组件会被渲染。
    • 相对路径 'address': 会被追加到父路径后面,形成完整的路径 /user/address

4. 工作原理与优势

完整流程解析

当用户访问 /user/address 时,路由的解析过程如下:

  1. 匹配父路由: 路由器首先在顶层路由中匹配路径。/user/address 成功匹配到 path: '/user' 的父路由。
  2. 渲染父组件: 路由器将父路由对应的 UserLayout.vue 组件渲染到根组件 App.vue<RouterView> 中。
  3. 匹配子路由: 此时,路由器会继续使用路径的剩余部分 (address) 在父路由的 children 数组中进行匹配。
  4. 渲染子组件: 路由器找到 path: 'address' 的子路由,并将其对应的 Address.vue 组件渲染到父组件 UserLayout.vue 内部的 <RouterView> 中。

(这是一个概念图,说明了组件的嵌套关系)

核心优势

  1. 代码复用 (Reusability): 公共的UI布局(如侧边栏、顶部导航、页脚)只需在布局组件中编写一次,所有子页面均可复用。
  2. 结构清晰 (Clear Structure): 路由配置的嵌套结构直观地反映了组件和页面UI的层级关系,使得项目结构更易于理解和维护。
  3. 无限嵌套 (Infinite Nesting): 嵌套路由不限于两层。任何一个子路由本身也可以拥有自己的 children 属性,实现三层、四层甚至更深层次的嵌套。例如,在“用户资料”页面内,还可以通过Tab选项卡进一步嵌套“基本资料”和“账户资料”等子视图。