Files
2026-11-11 18:42:09 +08:00

107 lines
2.1 KiB
Vue

<template>
<view class="app-tabbar">
<view class="tabbar-inner">
<view
v-for="tab in list"
:key="tab.name"
class="tab-item"
:class="{ active: current === tab.name }"
@tap="onChange(tab.name)"
>
<FaIcon
:name="tab.icon"
:color="current === tab.name ? '#2563eb' : '#94a3b8'"
:size="20"
/>
<text class="tab-text">{{ tab.text }}</text>
</view>
</view>
<view class="safe-area" />
</view>
</template>
<script setup>
import { computed } from 'vue'
/**
* 主 tabbar —— 默认「工作台 / 应用 / 我的」。
* 传入 tabs 时按自定义页签渲染(个人中心用「我的 / 回平台」两项);
* name=platform 为特殊动作:清空页面栈回到平台模块选择页。
*/
const props = defineProps({
current: {
type: String,
default: 'dashboard'
},
tabs: {
type: Array,
default: null
}
})
const DEFAULT_TABS = [
{ name: 'dashboard', text: '工作台', icon: 'grip' },
{ name: 'features', text: '应用', icon: 'th-large' },
{ name: 'profile', text: '我的', icon: 'user' }
]
const list = computed(() => (props.tabs && props.tabs.length ? props.tabs : DEFAULT_TABS))
const routes = {
dashboard: '/pages/dashboard/dashboard',
features: '/pages/features/features',
profile: '/pages/profile/profile'
}
function onChange(name) {
if (name === 'platform') {
uni.reLaunch({ url: '/pages/nav/nav' })
return
}
if (name === props.current || !routes[name]) return
uni.redirectTo({ url: routes[name] })
}
</script>
<style lang="scss" scoped>
@import '@/src/styles/theme.scss';
.app-tabbar {
flex-shrink: 0;
background: $color-card;
border-top: 1rpx solid $color-border;
box-shadow: $shadow-header;
}
.tabbar-inner {
display: flex;
align-items: center;
justify-content: space-around;
padding: 10rpx 0 6rpx;
}
.tab-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 4rpx;
padding: 8rpx 0;
&.active .tab-text {
color: $color-primary;
font-weight: 600;
}
}
.tab-text {
font-size: 22rpx;
color: $color-text-muted;
}
.safe-area {
height: constant(safe-area-inset-bottom);
height: env(safe-area-inset-bottom);
}
</style>