327 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
			
		
		
	
	
			327 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
| <template>
 | ||
|   <view class="raised-tabbar">
 | ||
|     <!-- 背景遮罩层,创建凸起效果 -->
 | ||
|     <view class="tabbar-bg">
 | ||
|       <view class="raised-circle"></view>
 | ||
|     </view>
 | ||
| 
 | ||
|     <!-- TabBar内容 -->
 | ||
|     <view class="tabbar-content">
 | ||
|       <!-- 左侧两个选项 -->
 | ||
|       <view
 | ||
|         v-for="(item, index) in leftItems"
 | ||
|         :key="index"
 | ||
|         class="tabbar-item"
 | ||
|         :class="{ active: current === index }"
 | ||
|         @click="tabbarChange(index)"
 | ||
|       >
 | ||
|         <view class="item-icon">
 | ||
|           <image
 | ||
|             :src="current === index ? item.activeIcon : item.inactiveIcon"
 | ||
|             class="icon-normal"
 | ||
|           />
 | ||
|           <view v-if="item.badge && item.badge > 0" class="badge">{{
 | ||
|             item.badge
 | ||
|           }}</view>
 | ||
|         </view>
 | ||
|         <text class="item-text" :class="{ active: current === index }">{{
 | ||
|           item.text
 | ||
|         }}</text>
 | ||
|       </view>
 | ||
| 
 | ||
|       <!-- 中间凸起的选项 -->
 | ||
|       <view
 | ||
|         class="tabbar-item center-item"
 | ||
|         :class="{ active: current === 2 }"
 | ||
|         @click="tabbarChange(2)"
 | ||
|         v-if="!newShareMember"
 | ||
|       >
 | ||
|         <view class="center-icon-wrapper">
 | ||
|           <view class="center-icon">
 | ||
|             <image
 | ||
|               :src="
 | ||
|                 current === 2 ? centerItem.activeIcon : centerItem.inactiveIcon
 | ||
|               "
 | ||
|               class="center-image"
 | ||
|             />
 | ||
|           </view>
 | ||
|         </view>
 | ||
|         <text
 | ||
|           class="item-text center-text"
 | ||
|           :class="{ active: current === 2 }"
 | ||
|           >{{ centerItem.text }}</text
 | ||
|         >
 | ||
|       </view>
 | ||
| 
 | ||
|       <!-- 右侧两个选项 -->
 | ||
|       <view
 | ||
|         v-for="(item, index) in rightItems"
 | ||
|         :key="index + 3"
 | ||
|         class="tabbar-item"
 | ||
|         :class="{ active: current === index + 3 }"
 | ||
|         @click="tabbarChange(index + 3)"
 | ||
|       >
 | ||
|         <view class="item-icon">
 | ||
|           <image
 | ||
|             :src="current === index + 3 ? item.activeIcon : item.inactiveIcon"
 | ||
|             class="icon-normal"
 | ||
|           />
 | ||
|           <view v-if="item.badge && item.badge > 0" class="badge">{{
 | ||
|             item.badge
 | ||
|           }}</view>
 | ||
|         </view>
 | ||
|         <text class="item-text" :class="{ active: current === index + 3 }">{{
 | ||
|           item.text
 | ||
|         }}</text>
 | ||
|       </view>
 | ||
|     </view>
 | ||
|   </view>
 | ||
| </template>
 | ||
| 
 | ||
| <script>
 | ||
| import { mapGetters } from 'vuex'
 | ||
| 
 | ||
| export default {
 | ||
|   name: 'RaisedTabbar',
 | ||
|   props: {
 | ||
|     current: {
 | ||
|       type: Number,
 | ||
|       default: 0,
 | ||
|     },
 | ||
|   },
 | ||
|   mounted() {
 | ||
|     this.newShareMember = uni.getStorageSync('User')?.loginType !== 0
 | ||
|   },
 | ||
|   data() {
 | ||
|     return {
 | ||
|       newShareMember: false,
 | ||
|       // 完整的路由列表
 | ||
|       list: [
 | ||
|         {
 | ||
|           text: '首页',
 | ||
|           path: 'pages/index/index',
 | ||
|         },
 | ||
|         {
 | ||
|           text: '会员专区',
 | ||
|           path: 'pages/specialArea/index',
 | ||
|         },
 | ||
|         {
 | ||
|           text: '个人推广',
 | ||
|           path: 'pages/mine/share/index',
 | ||
|         },
 | ||
|         {
 | ||
|           text: '购物车',
 | ||
|           path: 'pages/shoppingCar/index',
 | ||
|         },
 | ||
|         {
 | ||
|           text: '我的',
 | ||
|           path: 'pages/mine/index',
 | ||
|         },
 | ||
|       ],
 | ||
|     }
 | ||
|   },
 | ||
|   computed: {
 | ||
|     ...mapGetters(['shopCarLength']),
 | ||
|     // 左侧两个选项
 | ||
|     leftItems() {
 | ||
|       return [
 | ||
|         {
 | ||
|           text: '首页',
 | ||
|           activeIcon: require('@/static/images/one1.png'),
 | ||
|           inactiveIcon: require('@/static/images/one2.png'),
 | ||
|         },
 | ||
|         {
 | ||
|           text: '会员专区',
 | ||
|           activeIcon: require('@/static/images/five1.jpg'),
 | ||
|           inactiveIcon: require('@/static/images/five2.jpg'),
 | ||
|         },
 | ||
|       ]
 | ||
|     },
 | ||
|     // 中间凸起选项
 | ||
|     centerItem() {
 | ||
|       return {
 | ||
|         text: '个人推广',
 | ||
|         activeIcon: require('@/static/images/code.svg'),
 | ||
|         inactiveIcon: require('@/static/images/code.svg'),
 | ||
|       }
 | ||
|     },
 | ||
|     // 右侧两个选项
 | ||
|     rightItems() {
 | ||
|       return [
 | ||
|         {
 | ||
|           text: '购物车',
 | ||
|           activeIcon: require('@/static/images/three1.png'),
 | ||
|           inactiveIcon: require('@/static/images/three2.png'),
 | ||
|           badge: this.shopCarLength,
 | ||
|         },
 | ||
|         {
 | ||
|           text: '我的',
 | ||
|           activeIcon: require('@/static/images/fore1.png'),
 | ||
|           inactiveIcon: require('@/static/images/fore2.png'),
 | ||
|         },
 | ||
|       ]
 | ||
|     },
 | ||
|   },
 | ||
|   methods: {
 | ||
|     tabbarChange(index) {
 | ||
|       this.$emit('change', index)
 | ||
|       uni.switchTab({
 | ||
|         url: '/' + this.list[index].path,
 | ||
|       })
 | ||
|     },
 | ||
|   },
 | ||
| }
 | ||
| </script>
 | ||
| 
 | ||
| <style lang="scss" scoped>
 | ||
| .raised-tabbar {
 | ||
|   position: fixed;
 | ||
|   bottom: 0;
 | ||
|   left: 0;
 | ||
|   right: 0;
 | ||
|   z-index: 1000;
 | ||
| 
 | ||
|   .tabbar-bg {
 | ||
|     position: absolute;
 | ||
|     bottom: 0;
 | ||
|     left: 0;
 | ||
|     right: 0;
 | ||
|     height: 60px;
 | ||
|     background: #ffffff;
 | ||
| 
 | ||
|     // 添加底部安全区域
 | ||
|     &::after {
 | ||
|       content: '';
 | ||
|       position: absolute;
 | ||
|       bottom: -40px;
 | ||
|       left: 0;
 | ||
|       right: 0;
 | ||
|       height: env(safe-area-inset-bottom);
 | ||
|       background: #ffffff;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   .tabbar-content {
 | ||
|     position: relative;
 | ||
|     display: flex;
 | ||
|     align-items: flex-end;
 | ||
|     height: 60px;
 | ||
|     padding-bottom: 5px;
 | ||
|     background: transparent;
 | ||
| 
 | ||
|     .tabbar-item {
 | ||
|       flex: 1;
 | ||
|       display: flex;
 | ||
|       flex-direction: column;
 | ||
|       align-items: center;
 | ||
|       justify-content: center;
 | ||
|       padding-bottom: 5px;
 | ||
|       position: relative;
 | ||
| 
 | ||
|       .item-icon {
 | ||
|         position: relative;
 | ||
|         margin-bottom: 2px;
 | ||
| 
 | ||
|         .icon-normal {
 | ||
|           width: 20px;
 | ||
|           height: 20px;
 | ||
|         }
 | ||
| 
 | ||
|         .badge {
 | ||
|           position: absolute;
 | ||
|           top: -5px;
 | ||
|           right: -8px;
 | ||
|           background: #ff4757;
 | ||
|           color: white;
 | ||
|           border-radius: 50%;
 | ||
|           width: 16px;
 | ||
|           height: 16px;
 | ||
|           font-size: 10px;
 | ||
|           text-align: center;
 | ||
|           line-height: 16px;
 | ||
|           display: flex;
 | ||
|           align-items: center;
 | ||
|           justify-content: center;
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       .item-text {
 | ||
|         font-size: 10px;
 | ||
|         color: #666666;
 | ||
|         line-height: 1.2;
 | ||
| 
 | ||
|         &.active {
 | ||
|           color: #333333;
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       // 中间凸起的特殊样式
 | ||
|       &.center-item {
 | ||
|         position: relative;
 | ||
| 
 | ||
|         .center-icon-wrapper {
 | ||
|           position: absolute;
 | ||
|           top: -58rpx;
 | ||
|           background: #fff;
 | ||
|           border-radius: 50%;
 | ||
|           font-size: 0;
 | ||
|           padding: 4rpx;
 | ||
|           z-index: 10;
 | ||
| 
 | ||
|           .center-icon {
 | ||
|             width: 92rpx;
 | ||
|             height: 92rpx;
 | ||
|             border-radius: 50%;
 | ||
|             display: flex;
 | ||
|             align-items: center;
 | ||
|             justify-content: center;
 | ||
|             // box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
 | ||
|             position: relative;
 | ||
|             // 添加呼吸动画
 | ||
|             // animation: breathe 3s ease-in-out infinite;
 | ||
| 
 | ||
|             .center-image {
 | ||
|               width: 92rpx;
 | ||
|               height: 92rpx;
 | ||
|               // position: absolute;
 | ||
|               // top: -10rpx;
 | ||
|             }
 | ||
| 
 | ||
|             // 活跃状态
 | ||
|             // &.active {
 | ||
|             //   background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
 | ||
|             // }
 | ||
|           }
 | ||
|         }
 | ||
| 
 | ||
|         .center-text {
 | ||
|           margin-top: 25px;
 | ||
|           font-size: 9px;
 | ||
|         }
 | ||
| 
 | ||
|         &.active {
 | ||
|           .center-icon-wrapper .center-icon {
 | ||
|             // background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
 | ||
|             transform: scale(1.1);
 | ||
|             transition: all 0.3s ease;
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| // 呼吸动画关键帧
 | ||
| @keyframes breathe {
 | ||
|   0%,
 | ||
|   100% {
 | ||
|     transform: scale(1);
 | ||
|     // box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
 | ||
|   }
 | ||
|   50% {
 | ||
|     transform: scale(1.05);
 | ||
|     // box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
 | ||
|   }
 | ||
| }
 | ||
| </style>
 |