|
|
@@ -0,0 +1,177 @@
|
|
|
+<template>
|
|
|
+ <view class="custom-tabbar" :style="{ paddingBottom: safeAreaBottom + 'px' }">
|
|
|
+ <view
|
|
|
+ class="tabbar-item"
|
|
|
+ v-for="(item, index) in tabList"
|
|
|
+ :key="index"
|
|
|
+ @click="handleTabClick(item, index)"
|
|
|
+ >
|
|
|
+ <view class="icon-wrapper">
|
|
|
+ <!-- 首页特殊处理:滚动后显示向上箭头 -->
|
|
|
+ <template v-if="index === 0 && showBackTop && currentIndex === 0">
|
|
|
+ <view class="back-top-icon">
|
|
|
+ <uni-icons type="arrow-up" size="24" color="#F8C008"></uni-icons>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <image
|
|
|
+ :src="currentIndex === index ? item.selectedIconPath : item.iconPath"
|
|
|
+ mode="aspectFit"
|
|
|
+ class="icon-img"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </view>
|
|
|
+ <text :class="['tabbar-text', { active: currentIndex === index || (index === 0 && showBackTop && currentIndex === 0) }]">
|
|
|
+ {{ index === 0 && showBackTop && currentIndex === 0 ? '顶部' : item.text }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed, onMounted } from 'vue';
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ // 当前选中的 tab 索引
|
|
|
+ current: {
|
|
|
+ type: Number,
|
|
|
+ default: 0
|
|
|
+ },
|
|
|
+ // 是否显示回到顶部(由首页传入)
|
|
|
+ showBackTop: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const emit = defineEmits(['tabChange', 'backTop']);
|
|
|
+
|
|
|
+// tabBar 配置
|
|
|
+const tabList = ref([
|
|
|
+ {
|
|
|
+ pagePath: '/pages/index/index',
|
|
|
+ iconPath: '/static/images/tabbar/1-001.png',
|
|
|
+ selectedIconPath: '/static/images/tabbar/1-003.png',
|
|
|
+ text: '首页'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ pagePath: '/pages/goods_cate/goods_cate',
|
|
|
+ iconPath: '/static/images/2-001.png',
|
|
|
+ selectedIconPath: '/static/images/2-003.png',
|
|
|
+ text: '分类'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ pagePath: '/pages/order_addcart/order_addcart',
|
|
|
+ iconPath: '/static/images/tabbar/3-001.png',
|
|
|
+ selectedIconPath: '/static/images/tabbar/3-003.png',
|
|
|
+ text: '购物车'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ pagePath: '/pages/user/index',
|
|
|
+ iconPath: '/static/images/tabbar/4-001.png',
|
|
|
+ selectedIconPath: '/static/images/tabbar/4-003.png',
|
|
|
+ text: '我的'
|
|
|
+ }
|
|
|
+]);
|
|
|
+
|
|
|
+const currentIndex = computed(() => props.current);
|
|
|
+
|
|
|
+// 安全区域底部高度
|
|
|
+const safeAreaBottom = ref(0);
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const systemInfo = uni.getSystemInfoSync();
|
|
|
+ safeAreaBottom.value = systemInfo.safeAreaInsets?.bottom || 0;
|
|
|
+});
|
|
|
+
|
|
|
+// 处理 tab 点击
|
|
|
+const handleTabClick = (item, index) => {
|
|
|
+ // 如果是首页且显示回到顶部状态,触发回到顶部
|
|
|
+ if (index === 0 && props.showBackTop && currentIndex.value === 0) {
|
|
|
+ emit('backTop');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果点击的是当前页,不做处理
|
|
|
+ if (index === currentIndex.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 切换 tab
|
|
|
+ emit('tabChange', index);
|
|
|
+ uni.switchTab({
|
|
|
+ url: item.pagePath
|
|
|
+ });
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.custom-tabbar {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-around;
|
|
|
+ align-items: center;
|
|
|
+ height: 160rpx;
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-top: 1rpx solid #e5e5e5;
|
|
|
+ z-index: 9999;
|
|
|
+
|
|
|
+ .tabbar-item {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 10rpx 0;
|
|
|
+
|
|
|
+ .icon-wrapper {
|
|
|
+ width: 50rpx;
|
|
|
+ height: 50rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ .icon-img {
|
|
|
+ width: 50rpx;
|
|
|
+ height: 50rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .back-top-icon {
|
|
|
+ width: 50rpx;
|
|
|
+ height: 50rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ animation: bounce 0.5s ease-in-out;
|
|
|
+
|
|
|
+ .icon-img {
|
|
|
+ width: 50rpx;
|
|
|
+ height: 50rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .tabbar-text {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #999999;
|
|
|
+ margin-top: 6rpx;
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ color: #F8C008;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes bounce {
|
|
|
+ 0%, 100% {
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+ 50% {
|
|
|
+ transform: translateY(-5rpx);
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|