Files
hejiu/components/TabBar.vue
T
cg d335ec290a refactor(app): 重构应用主题和页面结构
- 移除动态主题切换功能,改为全局统一深色主题
- 实现自定义TabBar组件替换原生tabBar,解决iOS闪白问题
- 创建main容器页面统一管理三个tab页面的生命周期和状态
- 将所有页面的onShow/onHide等生命周期方法迁移到子组件内部
- 更新页面路径从index改为main,并调整路由跳转逻辑
- 移除theme-mixin和相关主题工具函数
- 统一页面背景色设置,优化用户体验一致性
2026-09-23 20:56:14 +08:00

108 lines
3.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!-- 自绘底部导航:替代微信原生 tabBar。点击只 emit change 交给容器切 v-show,
不走 switchTab 页面过渡,从根源消除 iOS WKWebView 重新栅格化导致的闪白。
配色沿用原生 tabBar:未选中 #9494AC、选中 #E8A838、背景 #151520。 -->
<view class="self-tabbar" :style="{ paddingBottom: safeBottom + 'px' }">
<view
v-for="(item, i) in items"
:key="i"
class="tab-item"
@click="onClick(i)"
>
<image
class="tab-icon"
:src="current === i ? item.activeIcon : item.icon"
mode="aspectFit"
/>
<text class="tab-text" :class="{ active: current === i }">{{ item.text }}</text>
</view>
</view>
</template>
<script>
export default {
name: 'TabBar',
props: {
// 当前选中的 tab 索引(home=0 / circle=1 / profile=2),由容器 main.vue 下发
current: {
type: Number,
default: 0
}
},
// Vue3 组件事件必须显式声明,否则可能触发异常/双触发
emits: ['change'],
data() {
// 底部安全区(iPhone 全面屏手势条),避免导航内容被手势条遮挡
let safeBottom = 0
try {
const sys = uni.getSystemInfoSync()
if (sys.safeAreaInsets && typeof sys.safeAreaInsets.bottom === 'number') {
safeBottom = sys.safeAreaInsets.bottom
} else if (sys.safeArea && sys.windowHeight) {
safeBottom = Math.max(0, sys.windowHeight - sys.safeArea.bottom)
}
} catch (e) { safeBottom = 0 }
return {
safeBottom,
items: [
{ text: '首页', icon: '/static/tab-home.png', activeIcon: '/static/tab-home-active.png' },
{ text: '酒友圈', icon: '/static/tab-circle.png', activeIcon: '/static/tab-circle-active.png' },
{ text: '我的', icon: '/static/tab-profile.png', activeIcon: '/static/tab-profile-active.png' }
]
}
},
methods: {
onClick(i) {
// 点击当前 tab 不重复触发,避免无谓的 pageShow 与滚动恢复
if (i === this.current) return
this.$emit('change', i)
}
}
}
</script>
<style lang="scss" scoped>
.self-tabbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
/* 高于子组件内部最高的 z-index:100(index/profile 存在 100 的 fixed/sticky 元素),确保导航稳定在最上层;
系统级 uni.showModal 不受此影响,仍会覆盖其上 */
z-index: 999;
display: flex;
/* 内容区固定 100rpx,安全区由 padding-bottom 额外承载;
box-sizing:content-box 确保总高 = 100rpx + safeBottom,与容器下发的 --tabbar-h 精确一致 */
height: 100rpx;
box-sizing: content-box;
background-color: #151520;
/* 顶部 1rpx 分隔线用 box-shadow 绘制,不占据高度(避免破坏 --tabbar-h 一致性) */
box-shadow: 0 -1rpx 0 0 rgba(255, 255, 255, 0.06);
}
.tab-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.tab-icon {
width: 44rpx;
height: 44rpx;
}
.tab-text {
margin-top: 4rpx;
font-size: 20rpx;
line-height: 1;
color: #9494AC;
transition: color 0.2s ease;
&.active {
color: #E8A838;
}
}
</style>