{T}

基本用法

路由配置

javascript
const routes = [
  {
    path: '/user',
    component: User,
    children: [
      {
        // 当 /user/profile 匹配成功
        // UserProfile 将被渲染在 User 的 <router-view> 中
        path: 'profile',
        component: UserProfile
      },
      {
        // 当 /user/posts 匹配成功
        path: 'posts',
        component: UserPosts
      }
    ]
  }
]

父组件

Vue SFC
<!-- User.vue -->
<template>
  <div class="user">
    <h1>用户中心</h1>
    
    <!-- 导航菜单 -->
    <nav>
      <router-link to="/user/profile">个人信息</router-link>
      <router-link to="/user/posts">我的文章</router-link>
    </nav>
    
    <!-- 子路由出口 -->
    <router-view></router-view>
  </div>
</template>

子组件

Vue SFC
<!-- UserProfile.vue -->
<template>
  <div class="profile">
    <h2>个人信息</h2>
    <p>用户名:{{ username }}</p>
  </div>
</template>
Vue SFC
<!-- UserPosts.vue -->
<template>
  <div class="posts">
    <h2>我的文章</h2>
    <ul>
      <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
    </ul>
  </div>
</template>

URL 匹配

URL渲染组件
/user/profileUser → UserProfile
/user/postsUser → UserPosts
/userUser(子路由出口为空)

子路由路径规则

/ 开头(绝对路径)

javascript
const routes = [
  {
    path: '/user',
    component: User,
    children: [
      {
        // 绝对路径,完整匹配 /profile
        path: '/profile',
        component: UserProfile
      }
    ]
  }
]

不以 / 开头(相对路径)

javascript
const routes = [
  {
    path: '/user',
    component: User,
    children: [
      {
        // 相对路径,自动拼接为 /user/profile
        path: 'profile',
        component: UserProfile
      }
    ]
  }
]

空路径子路由

javascript
const routes = [
  {
    path: '/user',
    component: User,
    children: [
      {
        // 空路径,匹配 /user
        path: '',
        component: UserHome
      },
      {
        path: 'profile',
        component: UserProfile
      }
    ]
  }
]
URL渲染组件
/userUser → UserHome
/user/profileUser → UserProfile

默认子路由

方式一:空路径

javascript
const routes = [
  {
    path: '/user',
    component: User,
    children: [
      {
        path: '',           // 空路径作为默认
        component: UserHome
      },
      {
        path: 'profile',
        component: UserProfile
      }
    ]
  }
]

方式二:命名路由

javascript
const routes = [
  {
    path: '/user',
    component: User,
    children: [
      {
        path: '',
        name: 'User',      // 父路由名称
        component: UserHome
      },
      {
        path: 'profile',
        name: 'UserProfile',
        component: UserProfile
      }
    ]
  }
]

// 导航到默认子路由
router.push({ name: 'User' })

多层嵌套

Vue Router 支持任意层级的路由嵌套。

三层嵌套示例

code
应用
└── /admin
    └── Admin
        ├── 侧边栏
        └── 内容区 (<router-view>)
            └── /admin/user
                └── UserManage
                    ├── 用户列表
                    └── 操作区 (<router-view>)
                        └── /admin/user/detail
                            └── UserDetail

路由配置

javascript
const routes = [
  {
    path: '/admin',
    component: Admin,
    children: [
      {
        path: 'user',
        component: UserManage,
        children: [
          {
            path: '',
            component: UserList
          },
          {
            path: 'detail/:id',
            component: UserDetail
          }
        ]
      },
      {
        path: 'product',
        component: ProductManage,
        children: [
          {
            path: '',
            component: ProductList
          },
          {
            path: 'create',
            component: ProductCreate
          }
        ]
      }
    ]
  }
]

组件结构

Admin.vue

Vue SFC
<template>
  <div class="admin">
    <aside class="sidebar">
      <router-link to="/admin/user">用户管理</router-link>
      <router-link to="/admin/product">商品管理</router-link>
    </aside>
    
    <main class="content">
      <router-view></router-view>
    </main>
  </div>
</template>

UserManage.vue

Vue SFC
<template>
  <div class="user-manage">
    <div class="list">
      <!-- 用户列表 -->
      <ul>
        <li v-for="user in users" :key="user.id">
          <router-link :to="`/admin/user/detail/${user.id}`">
            {{ user.name }}
          </router-link>
        </li>
      </ul>
    </div>
    
    <div class="detail">
      <router-view></router-view>
    </div>
  </div>
</template>

UserDetail.vue

Vue SFC
<template>
  <div class="user-detail">
    <h2>用户详情</h2>
    <p>ID: {{ $route.params.id }}</p>
  </div>
</template>

URL 层级结构

URL组件渲染链
/admin/userAdmin → UserManage → UserList
/admin/user/detail/123Admin → UserManage → UserDetail
/admin/productAdmin → ProductManage → ProductList
/admin/product/createAdmin → ProductManage → ProductCreate

动态嵌套路由

结合动态路由和嵌套路由:

javascript
const routes = [
  {
    path: '/user/:id',
    component: User,
    children: [
      {
        path: 'profile',
        component: UserProfile
      },
      {
        path: 'posts',
        component: UserPosts
      }
    ]
  }
]

访问父路由参数

子组件可以访问父路由的参数:

Vue SFC
<!-- UserPosts.vue -->
<template>
  <div>
    <h2>用户文章</h2>
    <p>用户 ID: {{ $route.params.id }}</p>
  </div>
</template>

动态导航

Vue SFC
<template>
  <div>
    <router-link :to="`/user/${userId}/profile`">个人信息</router-link>
    <router-link :to="`/user/${userId}/posts`">文章列表</router-link>
  </div>
</template>

<script>
export default {
  computed: {
    userId() {
      return this.$route.params.id
    }
  }
}
</script>

实战案例:后台管理系统

项目结构

code
views/
├── layout/
│   └── AdminLayout.vue     # 后台布局
├── dashboard/
│   └── Dashboard.vue       # 仪表盘
├── user/
│   ├── UserList.vue        # 用户列表
│   ├── UserDetail.vue      # 用户详情
│   └── UserCreate.vue      # 创建用户
├── product/
│   ├── ProductList.vue     # 商品列表
│   └── ProductEdit.vue     # 编辑商品
└── settings/
    ├── Profile.vue         # 个人设置
    └── Security.vue        # 安全设置

完整路由配置

javascript
// router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    redirect: '/admin'
  },
  {
    path: '/admin',
    component: () => import('@/views/layout/AdminLayout.vue'),
    meta: { requiresAuth: true },
    children: [
      {
        path: '',
        redirect: '/admin/dashboard'
      },
      {
        path: 'dashboard',
        name: 'Dashboard',
        component: () => import('@/views/dashboard/Dashboard.vue'),
        meta: { title: '仪表盘' }
      },
      {
        path: 'user',
        name: 'UserManage',
        component: { render: h => h('router-view') }, // 空容器
        meta: { title: '用户管理' },
        children: [
          {
            path: '',
            name: 'UserList',
            component: () => import('@/views/user/UserList.vue'),
            meta: { title: '用户列表' }
          },
          {
            path: 'create',
            name: 'UserCreate',
            component: () => import('@/views/user/UserCreate.vue'),
            meta: { title: '创建用户' }
          },
          {
            path: ':id',
            name: 'UserDetail',
            component: () => import('@/views/user/UserDetail.vue'),
            props: true,
            meta: { title: '用户详情' }
          }
        ]
      },
      {
        path: 'product',
        name: 'ProductManage',
        component: { render: h => h('router-view') },
        meta: { title: '商品管理' },
        children: [
          {
            path: '',
            name: 'ProductList',
            component: () => import('@/views/product/ProductList.vue'),
            meta: { title: '商品列表' }
          },
          {
            path: 'edit/:id?',
            name: 'ProductEdit',
            component: () => import('@/views/product/ProductEdit.vue'),
            props: true,
            meta: { title: '编辑商品' }
          }
        ]
      },
      {
        path: 'settings',
        name: 'Settings',
        component: { render: h => h('router-view') },
        meta: { title: '系统设置' },
        children: [
          {
            path: '',
            redirect: 'profile'
          },
          {
            path: 'profile',
            name: 'Profile',
            component: () => import('@/views/settings/Profile.vue'),
            meta: { title: '个人设置' }
          },
          {
            path: 'security',
            name: 'Security',
            component: () => import('@/views/settings/Security.vue'),
            meta: { title: '安全设置' }
          }
        ]
      }
    ]
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/Login.vue')
  },
  {
    path: '*',
    component: () => import('@/views/NotFound.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

布局组件

AdminLayout.vue

Vue SFC
<template>
  <el-container class="admin-layout">
    <!-- 侧边栏 -->
    <el-aside width="200px">
      <div class="logo">管理后台</div>
      <el-menu
        :default-active="activeMenu"
        router
      >
        <el-menu-item index="/admin/dashboard">
          <i class="el-icon-menu"></i>
          <span>仪表盘</span>
        </el-menu-item>
        
        <el-submenu index="user">
          <template #title>
            <i class="el-icon-user"></i>
            <span>用户管理</span>
          </template>
          <el-menu-item index="/admin/user">用户列表</el-menu-item>
          <el-menu-item index="/admin/user/create">创建用户</el-menu-item>
        </el-submenu>
        
        <el-submenu index="product">
          <template #title>
            <i class="el-icon-goods"></i>
            <span>商品管理</span>
          </template>
          <el-menu-item index="/admin/product">商品列表</el-menu-item>
        </el-submenu>
        
        <el-submenu index="settings">
          <template #title>
            <i class="el-icon-setting"></i>
            <span>系统设置</span>
          </template>
          <el-menu-item index="/admin/settings/profile">个人设置</el-menu-item>
          <el-menu-item index="/admin/settings/security">安全设置</el-menu-item>
        </el-submenu>
      </el-menu>
    </el-aside>
    
    <!-- 主内容区 -->
    <el-container>
      <el-header>
        <div class="header-content">
          <span>{{ pageTitle }}</span>
          <div class="user-info">
            <span>{{ username }}</span>
            <el-button type="text" @click="logout">退出</el-button>
          </div>
        </div>
      </el-header>
      
      <el-main>
        <router-view v-slot="{ Component }">
          <transition name="fade" mode="out-in">
            <component :is="Component" />
          </transition>
        </router-view>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
export default {
  name: 'AdminLayout',
  computed: {
    activeMenu() {
      return this.$route.path
    },
    pageTitle() {
      return this.$route.meta.title || '管理后台'
    },
    username() {
      return this.$store.state.user.username
    }
  },
  methods: {
    logout() {
      this.$store.dispatch('user/logout')
      this.$router.push('/login')
    }
  }
}
</script>

<style scoped>
.admin-layout {
  height: 100vh;
}

.logo {
  height: 60px;
  line-height: 60px;
  text-align: center;
  font-size: 18px;
  font-weight: bold;
  background: #2d3a4b;
  color: #fff;
}

.el-header {
  background: #fff;
  border-bottom: 1px solid #e6e6e6;
  display: flex;
  align-items: center;
}

.header-content {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.el-aside {
  background: #2d3a4b;
  color: #fff;
}
</style>

最佳实践

1. 合理控制嵌套层级

javascript
// ❌ 不推荐:嵌套层级过深
{
  path: '/a',
  component: A,
  children: [
    {
      path: 'b',
      component: B,
      children: [
        {
          path: 'c',
          component: C,
          children: [
            {
              path: 'd',
              component: D
            }
          ]
        }
      ]
    }
  ]
}

// ✅ 推荐:扁平化路由结构
{
  path: '/a/b/c/d',
  component: D
}

2. 使用布局组件

javascript
// 布局组件作为父路由
{
  path: '/admin',
  component: AdminLayout,  // 包含侧边栏和顶部栏
  children: [
    { path: 'user', component: UserManage },
    { path: 'product', component: ProductManage }
  ]
}

3. 空容器组件

当需要多级嵌套但中间层不需要渲染时:

javascript
{
  path: '/user',
  component: { render: h => h('router-view') }, // 空容器
  children: [
    { path: 'list', component: UserList },
    { path: 'detail/:id', component: UserDetail }
  ]
}

4. 统一设置路由元信息

javascript
{
  path: '/admin',
  component: AdminLayout,
  meta: { requiresAuth: true },  // 父路由设置
  children: [
    {
      path: 'user',
      component: UserManage,
      meta: { title: '用户管理' }  // 子路由继承父路由 meta
    }
  ]
}

5. 懒加载子路由组件

javascript
{
  path: '/admin',
  component: () => import('@/views/AdminLayout.vue'),
  children: [
    {
      path: 'user',
      component: () => import('@/views/UserManage.vue')  // 懒加载
    }
  ]
}

常见问题

1. 子路由不显示?

检查父组件是否包含 <router-view>

Vue SFC
<!-- 父组件必须有 router-view -->
<template>
  <div>
    <router-view></router-view>
  </div>
</template>

2. 如何设置默认子路由?

javascript
{
  path: '/user',
  component: User,
  children: [
    {
      path: '',           // 空路径作为默认
      component: UserHome
    }
  ]
}

3. 子路由路径要不要加 /

  • /:绝对路径,不拼接父路径
  • 不加 /:相对路径,自动拼接父路径
javascript
children: [
  { path: 'profile' }      // 相对路径 → /user/profile
  { path: '/profile' }     // 绝对路径 → /profile
]

4. 如何获取所有层级的路由参数?

javascript
// 假设路由为 /user/:userId/post/:postId
{
  path: '/user/:userId',
  component: User,
  children: [
    {
      path: 'post/:postId',
      component: Post
    }
  ]
}

// 在 Post 组件中
this.$route.params  // { userId: '123', postId: '456' }

调试技巧

查看 matched 路由记录

javascript
// 查看当前路由的所有嵌套记录
console.log(this.$route.matched)
// 输出:[{ path: '/admin' }, { path: '/admin/user' }, { path: '/admin/user/detail' }]

检查组件嵌套层级

javascript
// 在路由守卫中
router.beforeEach((to, from, next) => {
  console.log('路由层级:', to.matched.length)
  console.log('路由记录:', to.matched)
  next()
})