项目采用单页面 + 组件切换的架构,实现类似原生TabBar的效果,同时保持头部和底部固定不变。
pages/
├── login/
│ └── login.vue # 登录页面(独立页面)
└── index.vue # 主容器页面(核心)
pages-content/ # 内容组件目录(独立)
├── home/
│ └── index.vue # 首页内容组件
├── scan/
│ └── index.vue # 扫描内容组件
└── my/
└── index.vue # 我的内容组件
┌─────────────────────────────┐
│ 自定义头部(固定) │ ← 白色背景,显示当前标题
│ - 自适应状态栏高度 │ 根据currentTab自动切换
├─────────────────────────────┤
│ │
│ 主内容区(动态切换) │ ← 使用 v-if 切换组件
│ - HomePage 组件 │ - currentTab = 'home'
│ - ScanPage 组件 │ - currentTab = 'scan'
│ - MyPage 组件 │ - currentTab = 'mine'
│ │
├─────────────────────────────┤
│ 自定义底部导航栏(固定) │ ← 白色背景,三个菜单
│ 🏠 首页 | 📷 扫描 | 👤 我的 │ 点击切换 currentTab
└─────────────────────────────┘
// 当前激活的tab
const currentTab = ref('home')
// 切换tab - 只需要改变currentTab值
const switchTab = (name) => {
if (currentTab.value === name) return
currentTab.value = name
}
// 标题自动跟随当前tab
const currentPageTitle = computed(() => {
const titles = {
home: '首页',
scan: '扫描',
mine: '我的'
}
return titles[currentTab.value] || '首页'
})
<view class="main-content">
<!-- 通过 v-if 实现组件切换 -->
<HomePage v-if="currentTab === 'home'" />
<ScanPage v-else-if="currentTab === 'scan'" />
<MyPage v-else-if="currentTab === 'mine'" />
</view>
<template>
<view class="home-page">
<view class="page-header">
<text class="title">首页内容</text>
</view>
<view class="page-body">
<text class="placeholder">首页主体内容区域</text>
</view>
</view>
</template>
特点:
<template>
<view class="scan-page">
<view class="page-header">
<text class="title">扫描内容</text>
</view>
<view class="page-body">
<text class="placeholder">扫描主体内容区域</text>
</view>
</view>
</template>
特点:
<template>
<view class="my-page">
<view class="page-header">
<text class="title">我的内容</text>
</view>
<view class="page-body">
<text class="placeholder">我的主体内容区域</text>
</view>
</view>
</template>
特点:
// pages/login/login.vue
uni.navigateTo({
url: '/pages/index' // 跳转到主容器页面
})
// pages/index.vue
switchTab('scan') // 切换到扫描页
// ↓
currentTab.value = 'scan'
// ↓
<ScanPage /> 组件显示
// ↓
头部标题变为"扫描"
// ↓
底部导航高亮"扫描"
| 操作 | 重新渲染 | 说明 |
|---|---|---|
| 初始加载 | 完整渲染 | 加载主容器 + 首页组件 |
| 切换tab | 只渲染内容 | 头部和底部不变 |
| 返回登录 | 完整渲染 | 卸载主容器 |
1. 创建内容组件
pages-content/newpage/index.vue
2. 在主容器中引入
<!-- pages/index.vue -->
<script setup>
import NewPage from '../pages-content/newpage/index.vue'
</script>
<template>
<NewPage v-else-if="currentTab === 'newpage'" />
</template>
3. 添加底部导航配置
const tabList = ref([
// ...现有配置
{
name: 'newpage',
label: '新页面',
icon: '🎯'
}
])
4. 添加标题映射
const currentPageTitle = computed(() => {
const titles = {
// ...
newpage: '新页面'
}
return titles[currentTab.value]
})
如果需要不同页面有不同的头部样式:
<!-- 方案1:使用 computed 动态样式 -->
<view
class="custom-header"
:style="{
background: headerBackground,
paddingTop: statusBarHeight + 'px'
}"
>
<text>{{ currentPageTitle }}</text>
</view>
<script>
const headerBackground = computed(() => {
const colors = {
home: '#ffffff',
scan: '#667eea',
mine: '#ffffff'
}
return colors[currentTab.value]
})
</script>
如果需要在内容组件间共享数据:
使用 Pinia Store
// store/tab.js
export const useTabStore = defineStore('tab', {
state: () => ({
sharedData: null
})
})
// 在任意组件中使用
import { useTabStore } from '@/store/tab'
const tabStore = useTabStore()
{
"pages": [
{
"path": "pages/login/login",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/index",
"style": {
"navigationStyle": "custom" // 使用自定义导航栏
}
}
]
}
注意:
tabBarpages/index.vue 实现pages-content/* 下的组件不需要在 pages.json 中注册这是一个轻量级、高性能的单页应用架构:
适合需要底部导航的小程序项目!