Home双router-view与布局切换逻辑

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-viewsome-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 实战,用真实项目代码来拆解。

相关推荐
lizi662 小时前
uniapp uview-plus 自定义动态验证
前端·vue.js·微信小程序
踩着两条虫2 小时前
VTJ.PRO 在线应用开发平台概览
前端·vue.js·人工智能
英俊潇洒美少年2 小时前
Vue reactive 底层 Proxy 完整流程(依赖收集 + 触发更新)
前端·javascript·vue.js
周万宁.FoBJ2 小时前
vue源码讲解之 effect解析 (仅包含在effect中使用reacitve情况)
前端·javascript·vue.js
周淳APP2 小时前
【VDOM,Diff算法,生命周期,并发请求】
前端·javascript·vue.js
哟哟耶耶2 小时前
vue3-<script setup>是Vue3.2+引入编译语法糖与编译器宏以及useSlots()和useAttrs()
前端·javascript·vue.js
给钱,谢谢!2 小时前
记录uni-app Vue3 慎用 Teleport,会导致页面栈混乱
前端·vue.js·uni-app
大白菜1号3 小时前
踩坑了!Postman 正常,但本地项目 406 (Not Acceptable)
vue.js·测试工具·postman
四千岁3 小时前
如何精准统计 Token 消耗,使用对账工具控制成本?
前端·javascript·vue.js