You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
4.6 KiB
Vue

<template>
<view class="tabbar-shell" :class="{ 'is-hidden': !tabbarVisible }">
<up-tabbar :value="activeIndex" :activeColor="activeColor" :inactiveColor="inactiveColor" :safeAreaInsetBottom="true"
:fixed="true" :placeholder="true" :border="false" @change="handleChange" zIndex="1000">
<up-tabbar-item v-for="(item, index) in tabList" :key="index" :text="item.text" :name="index">
<template #active-icon>
<uni-icons v-if="item.iconType === 'uni-icons'" :type="item.iconName" size="30" :color="activeColor" />
<u-icon v-else-if="item.iconType === 'uview-plus'" :name="item.iconName" size="30" :color="activeColor"></u-icon>
<image v-else :src="item.selectedIcon" class="tabbar-icon" mode="widthFix" />
</template>
<template #inactive-icon>
<uni-icons v-if="item.iconType === 'uni-icons'" :type="item.iconName" size="30" :color="inactiveColor" />
<u-icon v-else-if="item.iconType === 'uview-plus'" :name="item.iconName" size="30" :color="inactiveColor"></u-icon>
<image v-else :src="item.icon" class="tabbar-icon" mode="widthFix" />
</template>
</up-tabbar-item>
</up-tabbar>
</view>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import useUserStore from '@/store/modules/user'
import { storeToRefs } from 'pinia'
import { getTabBarMenus } from '@/utils/permissionMenu'
const TABBAR_VISIBILITY_EVENT = 'tabbar-visibility-change'
const userStore = useUserStore()
const { menus } = storeToRefs(userStore)
const inactiveColor = '#666666'
const activeColor = '#409eff'
const activeIndex = ref(0)
const tabbarVisible = ref(true)
function normalizeRoute(path = '') {
return String(path || '').trim().replace(/^\/+/, '')
}
function isUniIcon(icon) {
return String(icon || '').startsWith('uni-icons:')
}
function isUviewIcon(icon) {
return String(icon || '').startsWith('uview-plus:')
}
function getUniIconName(icon) {
return String(icon || '').replace(/^uni-icons:/, '').trim()
}
function getUviewIconName(icon) {
return String(icon || '').replace(/^uview-plus:/, '').trim()
}
function resolveTabIconMeta(menu) {
if (isUniIcon(menu?.icon)) {
return {
iconType: 'uni-icons',
iconName: getUniIconName(menu.icon)
}
}
if (isUviewIcon(menu?.icon)) {
return {
iconType: 'uview-plus',
iconName: getUviewIconName(menu.icon)
}
}
return {
iconType: '',
iconName: '',
icon: '',
selectedIcon: ''
}
}
function getCurrentActiveIndex() {
const pages = getCurrentPages()
if (pages && pages.length > 0) {
const route = pages[pages.length - 1].route
const currentIndex = tabList.value.findIndex((item) => normalizeRoute(item.path) === route)
return currentIndex >= 0 ? currentIndex : 0
}
return 0
}
const tabList = computed(() => {
return getTabBarMenus(menus.value)
.map((menu) => {
const iconMeta = resolveTabIconMeta(menu)
return {
text: String(menu.name || menu.enName || '').trim(),
icon: iconMeta.icon,
selectedIcon: iconMeta.selectedIcon,
iconType: iconMeta.iconType,
iconName: iconMeta.iconName,
path: menu.path
}
})
})
onMounted(() => {
activeIndex.value = getCurrentActiveIndex()
uni.$on(TABBAR_VISIBILITY_EVENT, handleTabbarVisibility)
})
onUnmounted(() => {
uni.$off(TABBAR_VISIBILITY_EVENT, handleTabbarVisibility)
})
function handleTabbarVisibility(visible = true) {
tabbarVisible.value = visible !== false
}
function handleChange(index) {
if (activeIndex.value === index) return
activeIndex.value = index
const item = tabList.value[index]
if (item) {
uni.reLaunch({
url: item.path
})
}
}
watch(() => useUserStore().menus, () => {
activeIndex.value = getCurrentActiveIndex()
})
</script>
<style lang="scss" scoped>
.tabbar-shell {
position: relative;
:deep(.u-tabbar) {
position: fixed !important;
left: 0;
right: 0;
bottom: 0 !important;
width: 100%;
z-index: 1000 !important;
transform: translateY(0);
opacity: 1;
will-change: transform, opacity;
transition: transform 0.36s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.24s ease;
}
:deep(.u-tabbar__content) {
z-index: 1000 !important;
}
&.is-hidden {
:deep(.u-tabbar) {
transform: translateY(calc(100% + 24rpx + env(safe-area-inset-bottom)));
opacity: 0;
pointer-events: none;
}
}
}
.tabbar-icon {
width: 48rpx;
height: 48rpx;
}
</style>
<style>
.u-tabbar {
flex: none !important;
}
.u-tabbar-item__text{
margin-top: 0 !important;
}
</style>