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>
 |