Home.vue 里为什么有两个 router-view?我看了三遍才读懂
如果你第一次看到
Home.vue里写了两个<router-view>,可能会困惑:这不是重复了吗? 其实不是。这两个出口,各守一个"平行世界"。
先看那段让人迷惑的代码
vue
<template>
<fragment>
<el-container class="cus-root-container">
<!-- 第一个 router-view:只在即时聊天全屏时出现 -->
<router-view
:key="$route.path"
v-if="$route.path == '/review-service/instant-messaging'
&& $store.state.instantMessaging.bScreenfullBut == true"
/>
<!-- 后台壳区域:只在非全屏时显示 -->
<site-bar v-if="!$store.state.instantMessaging.bScreenfullBut" />
<el-container class="cus-right-wrap"
v-if="!$store.state.instantMessaging.bScreenfullBut">
<el-header class="cus-header">
<personal-bar />
<tabs-bar />
</el-header>
<el-main class="cus-main">
<keep-alive :exclude="excludelist">
<!-- 第二个 router-view:后台正常模式的内容出口 -->
<router-view :key="$route.path" />
</keep-alive>
</el-main>
</el-container>
</el-container>
</fragment>
</template>
初看很乱,但把它分成两块就很清楚了。
🗺️ 一张图搞懂两个出口
sql
Home.vue
├─ 🖥️ 全屏分支(上面那个 router-view)
│ └─ 条件:路由 = IM 页 && 全屏状态 = true
│ └─ 效果:聊天页面完全接管屏幕,没有侧边栏和顶部栏
│
└─ 🖥️ 普通后台分支(下面那个 router-view)
└─ 条件:全屏状态 = false
└─ 效果:正常后台布局,有侧边栏、顶部栏、标签页
└─ 外面套了 keep-alive 做页面缓存
它们永远不会同时出现。 因为 v-if 条件互斥:
- 全屏状态为
true→ 上面显示,下面隐藏 - 全屏状态为
false→ 下面显示,上面隐藏
📺 第一个 router-view:即时聊天全屏模式
触发条件
ini
当前路由是 /review-service/instant-messaging
+ Vuex 里 bScreenfullBut == true
两个条件同时满足,才会走这个出口。
它解决什么问题
即时聊天页面有一个**"全屏按钮"**。
用户点击全屏后,希望聊天窗口占满整个屏幕,不要有侧边菜单、顶部栏这些干扰。
但这个操作不是跳转到另一个页面,而是原地切换布局。
所以需要一个"纯净出口"------只渲染聊天页面本身,不带任何后台壳。
这就是第一个 router-view 存在的意义。
📋 第二个 router-view:日常后台模式
vue
<keep-alive :exclude="excludelist">
<router-view :key="$route.path" />
</keep-alive>
这是最常用的那个出口。
整个后台系统 90% 的页面都走这里渲染。
为什么外面套了 keep-alive?
后台系统的页面有一个特点:
用户在列表页设了很多筛选条件
→ 跳去详情页看了一会儿
→ 返回列表页
→ 希望筛选条件还在!
如果没有 keep-alive,每次返回都会重新创建组件,状态全丢。
加了 keep-alive 之后,组件实例被缓存起来,切回去时状态原封不动。
为什么要有 excludelist?
keep-alive 虽然好用,但不是所有页面都适合缓存。
有些页面每次进入都应该是"全新"的,比如:
- 编辑页:如果缓存了上次编辑的数据,会出现"脏数据"问题
- 详情页:缓存后可能显示旧记录,而不是当前要看的那条
- 表单创建页:上次填的内容不该保留
这些页面的 name 会被写进 excludelist,从而绕过缓存,每次都重建。
🔑 两个 router-view 都写了 :key="$route.path",为什么?
这是一个很容易忽略的细节。
如果不加 :key,Vue 在某些路由切换时会复用旧的组件实例,导致:
- 生命周期钩子没有重新触发
- 旧数据没清空
- 表单状态异常
加了 :key="$route.path" 之后:
- 每个路由路径对应一个唯一标识
- 路由一变,
key就变,Vue 就知道需要重新创建这个组件 - 页面切换更干净、更可控
🔄 路由和 Home.vue 的关系
你可能会看到很多路由这样配置:
js
{
path: '/some-path',
component: () => import('../views/Home.vue'), // 注意这里是 Home.vue
children: [
{
path: '',
component: () => import('../views/some-page.vue'),
}
]
}
这里的意思是:
- 进入这个路由,先用
Home.vue作为壳 Home.vue再通过router-view把some-page.vue渲染出来
所以:
bash
router/index.js → 决定"哪个页面进 Home"
Home.vue → 决定"这个页面以什么布局显示"
路由配置管"谁进来",Home.vue 管"怎么展示"。
✅ 怎么判断一个页面走哪个出口
看到一个页面时,可以按这个逻辑判断:
sql
if (路由是 IM 页 && 全屏状态 == true) {
走第一个 router-view → 全屏,没有后台壳
} else {
走第二个 router-view → 正常后台模式,有侧边栏顶部栏
}
🏁 一句话总结
sql
两个 router-view 不是重复,是两种布局的切换开关:
上面 → 即时聊天全屏专用出口
下面 → 普通后台模式 + keep-alive 缓存
条件互斥,永远不会同时工作
这是 Vue2 学习系列第三篇。
下一篇:Vue 生命周期 + keep-alive 实战,用真实项目代码来拆解。