一、前言
后台管理系统的标准长相:顶栏 + 侧边菜单 + 内容区,点菜单只有内容区变 ,顶栏侧栏纹丝不动。这就是嵌套路由的战场:路由里套路由,页面里套页面。本篇用 children 配置搭出后台布局雏形,顺带认识命名视图。
二、嵌套路由:路由里套路由
场景:/admin 下的"个人资料"和"系统设置"两个子页面,共享一个后台布局。
ts
// src/router/index.ts
import AdminLayout from '@/views/AdminLayout.vue'
const routes = [
{
path: '/admin',
component: AdminLayout, // 父路由:布局页
children: [ // ★ 子路由数组
{
// 注意:子路由 path 不以 / 开头(相对父路径)
path: 'profile',
name: 'admin-profile',
component: () => import('@/views/admin/ProfileView.vue')
},
{
path: 'settings',
name: 'admin-settings',
component: () => import('@/views/admin/SettingsView.vue')
}
]
}
]
父组件 AdminLayout 里挖第二个出口:
vue
<!-- src/views/AdminLayout.vue -->
<template>
<div class="admin">
<aside class="side">
<h3>后台管理</h3>
<!-- 子路由链接:to 写完整路径 -->
<RouterLink to="/admin/profile">个人资料</RouterLink>
<RouterLink to="/admin/settings">系统设置</RouterLink>
</aside>
<main class="content">
<!-- 二号出口:子路由组件渲染在这里 -->
<RouterView />
</main>
</div>
</template>
<style scoped>
.admin { display: flex; min-height: 200px; border: 1px solid #eee; }
.side { width: 140px; background: #f5f5f5; padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.content { flex: 1; padding: 16px; }
</style>
结构一层套一层:URL /admin/profile 匹配 AdminLayout → 其内部 RouterView 再渲染 ProfileView。子路由的出口永远在父组件的 RouterView 里 ------访问 /admin/profile 时 App.vue 的出口渲染 AdminLayout,AdminLayout 的出口渲染 ProfileView,两层同时渲染。
【截图位置:点击侧边菜单只有内容区变化的效果】
三、两个必会细节:默认子路由与"不写 /"
1. 子路由 path 不以 / 开头 :path: 'profile' 相对拼接成 /admin/profile。写了 /profile 会变成顶级路由 /profile(脱离父布局)------子路由斜杠必须省,这是新人第一大坑。
2. 默认子路由 :访问 /admin(不带子路径)时显示什么?给 children 加一条空 path 的子路由:
ts
children: [
{
path: '', // 空字符串 = 默认子路由
redirect: { name: 'admin-profile' } // 方案 A:重定向到 profile
},
{
path: 'profile',
name: 'admin-profile',
component: () => import('@/views/admin/ProfileView.vue')
},
// ...
]
或者直接给空 path 配组件(/admin 本身就渲染 profile 内容):
ts
{
path: '', // 方案 B:/admin 直接渲染默认页
name: 'admin-home',
component: () => import('@/views/admin/ProfileView.vue')
}
方案 A(redirect)语义更清晰,企业里常用。
四、多级嵌套:children 里还有 children
ts
{
path: '/admin',
component: AdminLayout,
children: [
{
path: 'settings',
component: () => import('@/views/admin/SettingsView.vue'),
children: [
{ path: 'basic', component: () => import('@/views/admin/SettingsBasic.vue') },
{ path: 'safe', component: () => import('@/views/admin/SettingsSafe.vue') }
]
}
]
}
SettingsView 里再放一个 RouterView 渲染 basic/safe。三层结构 = 三个 RouterView 同时渲染。嵌套别超过三四层(024 篇套娃警告在路由里同样生效),太深说明信息架构有问题。
五、命名视图:一个页面多个出口
嵌套路由是"父子关系",命名视图是"兄弟并排"------同一层挖几个坑,按名字填:
ts
// 同一个 path,配多个组件
{
path: '/dashboard',
components: { // ★ 注意 components 复数
default: () => import('@/views/dash/MainView.vue'), // 无名出口
sidebar: () => import('@/views/dash/SideView.vue'), // 名叫 sidebar 的出口
header: () => import('@/views/dash/HeaderView.vue') // 名叫 header 的出口
}
}
vue
<!-- 模板里按名字认领 -->
<template>
<RouterView name="header" />
<div class="row">
<RouterView name="sidebar" />
<RouterView /> <!-- 不写 name = default -->
</div>
</template>
使用频率不高(布局通常一个出口够用),但 el-container 布局 + 多区域路由的场景会遇到,认识即可。
六、综合实战:后台布局雏形(完整代码)
把默认子路由 + 侧边菜单 + 内容区整合成可运行版本:
ts
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import AdminLayout from '@/views/AdminLayout.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{ path: '/', name: 'home', component: () => import('@/views/HomeView.vue') },
{
path: '/admin',
component: AdminLayout,
children: [
{ path: '', redirect: { name: 'admin-profile' } },
{
path: 'profile',
name: 'admin-profile',
component: () => import('@/views/admin/ProfileView.vue')
},
{
path: 'settings',
name: 'admin-settings',
component: () => import('@/views/admin/SettingsView.vue')
}
]
}
]
})
export default router
vue
<!-- src/views/admin/ProfileView.vue -->
<template><h4>👤 个人资料页</h4><p>只有内容区在变</p></template>
vue
<!-- src/views/admin/SettingsView.vue -->
<template><h4>⚙️ 系统设置页</h4><p>顶栏侧栏毫无反应</p></template>
AdminLayout 用第四节那份(含样式)。跑起来:/admin 自动重定向到 profile,点菜单切换子页面,布局层稳如泰山------这就是 068 篇后台骨架的地基。
【截图位置:/admin 默认进入 profile、切换 settings 的运行效果】
七、踩坑记录
- 子路由 path 带了 / :
path: '/profile'变成顶级路由,脱离父布局,访问 /admin/profile 匹配不到------子路由一律省斜杠 - 忘了在父组件放 RouterView:子路由匹配成功但页面只显示布局、内容空白------父组件没挖坑
- RouterLink 的 to 写了相对路径 :
<RouterLink to="profile">在嵌套里行为随当前 URL 变化,容易错------to 永远写完整路径或按 name 跳 - 默认子路由写成 path: '/' :空 path 是
'','/' 在 children 里是非法/诡异行为 - components 单复数搞混 :命名视图用
components(复数)+RouterView name;普通嵌套用component(单数)
八、今日小结
- children 嵌套:父组件里挖第二个 RouterView,子路由 path 不带 /、to 写全路径
- 默认子路由:空 path + redirect(或直接配组件)
- 多级嵌套 = 多层出口同时渲染,控制在三四层内
- 命名视图:components 复数 + RouterView name,同级多出口(低频,认识即可)
下篇预告
后台布局有了,但谁都能访问 /admin 吗?下一篇 049 路由守卫------全局前置守卫、路由独享守卫、组件内守卫三级关卡,手写登录拦截完整流程。