关键在于插槽与动态组件协同:插槽作为内容容器预留位置,动态组件通过:is按需挂载页面,配合keep-alive缓存、状态隔离、图标联动、过渡动画及无障碍支持,实现原生级底部导航体验。

直接用插槽实现手机 App 风格的底部导航栏,关键不在于“插槽本身”,而在于它如何配合动态组件(component + is)完成内容区域的灵活切换。插槽负责承载当前页面主体,动态组件负责按需加载对应 Fragment 或页面模块,两者分工明确:插槽是“容器位置”,动态组件是“内容来源”。
底部导航栏结构用插槽预留内容区
在主布局(如 MainLayout.vue 或 Activity 容器)中,定义一个具名插槽(例如 #default 或 #content)作为页面主体的占位区:
- 这个插槽不写死任何具体组件,只留出空间和样式约束(比如设为 flex 主体、避免被导航栏遮挡);
- 导航栏(
BottomNav)独立存在,通常固定在底部,通过 emit 或事件总线通知父级切换当前页面标识; - 父级组件根据当前选中项,决定传入插槽的是哪个组件——这时就轮到动态组件上场。
用 动态挂载页面
将插槽内容替换为一个动态组件,其 :is 值由当前路由或状态控制:
- 预先定义好各页面组件,如
HomeView、SearchView、ProfileView; - 维护一个响应式变量(如
currentView),初始值为HomeView; - 点击底部 Tab 时,更新
currentView,自动卸载旧组件、挂载新组件; - 搭配
keep-alive可缓存已加载页面,避免重复初始化和滚动位置丢失。
插槽与动态组件协同的关键细节
真正让体验接近原生 App 的,是几个容易忽略但影响显著的设计点:
- 状态隔离:每个页面组件应管理自身数据和生命周期,不要依赖外部传入大量 props;
-
图标与文字联动:底部 Tab 的选中状态应与
currentView同步,可通过映射表(如{ home: HomeView })统一管理; -
过渡动画:在
外包裹,配合position: absolute实现页面滑入滑出; -
无障碍支持:为每个 Tab 设置
aria-current="page",并确保插槽内容区域有明确的role="main"。
不推荐纯插槽硬编码多个页面
有人会把所有页面都写成插槽的默认内容分支,靠 v-if 切换——这看似简单,实则违背插槽设计初衷,且导致模板臃肿、逻辑耦合、无法复用。插槽适合“内容注入”,不是“条件渲染容器”。动态组件才是解耦页面与导航逻辑的正解。









