index.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <template>
  2. <view class="custom-tabbar" :style="{ paddingBottom: safeAreaBottom + 'px' }">
  3. <view
  4. class="tabbar-item"
  5. v-for="(item, index) in tabList"
  6. :key="index"
  7. @click="handleTabClick(item, index)"
  8. >
  9. <view class="icon-wrapper">
  10. <!-- 首页特殊处理:滚动后显示向上箭头 -->
  11. <template v-if="index === 0 && showBackTop && currentIndex === 0">
  12. <view class="back-top-icon">
  13. <uni-icons type="arrow-up" size="24" color="#F8C008"></uni-icons>
  14. </view>
  15. </template>
  16. <template v-else>
  17. <image
  18. :src="currentIndex === index ? item.selectedIconPath : item.iconPath"
  19. mode="aspectFit"
  20. class="icon-img"
  21. />
  22. </template>
  23. </view>
  24. <text :class="['tabbar-text', { active: currentIndex === index || (index === 0 && showBackTop && currentIndex === 0) }]">
  25. {{ index === 0 && showBackTop && currentIndex === 0 ? '顶部' : item.text }}
  26. </text>
  27. </view>
  28. </view>
  29. </template>
  30. <script setup>
  31. import { ref, computed, onMounted } from 'vue';
  32. const props = defineProps({
  33. // 当前选中的 tab 索引
  34. current: {
  35. type: Number,
  36. default: 0
  37. },
  38. // 是否显示回到顶部(由首页传入)
  39. showBackTop: {
  40. type: Boolean,
  41. default: false
  42. }
  43. });
  44. const emit = defineEmits(['tabChange', 'backTop']);
  45. // tabBar 配置
  46. const tabList = ref([
  47. {
  48. pagePath: '/pages/index/index',
  49. iconPath: '/static/images/tabbar/1-001.png',
  50. selectedIconPath: '/static/images/tabbar/1-003.png',
  51. text: '首页'
  52. },
  53. {
  54. pagePath: '/pages/goods_cate/goods_cate',
  55. iconPath: '/static/images/2-001.png',
  56. selectedIconPath: '/static/images/2-003.png',
  57. text: '分类'
  58. },
  59. {
  60. pagePath: '/pages/order_addcart/order_addcart',
  61. iconPath: '/static/images/tabbar/3-001.png',
  62. selectedIconPath: '/static/images/tabbar/3-003.png',
  63. text: '购物车'
  64. },
  65. {
  66. pagePath: '/pages/user/index',
  67. iconPath: '/static/images/tabbar/4-001.png',
  68. selectedIconPath: '/static/images/tabbar/4-003.png',
  69. text: '我的'
  70. }
  71. ]);
  72. const currentIndex = computed(() => props.current);
  73. // 安全区域底部高度
  74. const safeAreaBottom = ref(0);
  75. onMounted(() => {
  76. const systemInfo = uni.getSystemInfoSync();
  77. safeAreaBottom.value = systemInfo.safeAreaInsets?.bottom || 0;
  78. });
  79. // 处理 tab 点击
  80. const handleTabClick = (item, index) => {
  81. // 如果是首页且显示回到顶部状态,触发回到顶部
  82. if (index === 0 && props.showBackTop && currentIndex.value === 0) {
  83. emit('backTop');
  84. return;
  85. }
  86. // 如果点击的是当前页,不做处理
  87. if (index === currentIndex.value) {
  88. return;
  89. }
  90. // 切换 tab
  91. emit('tabChange', index);
  92. uni.switchTab({
  93. url: item.pagePath
  94. });
  95. };
  96. </script>
  97. <style lang="scss" scoped>
  98. .custom-tabbar {
  99. position: fixed;
  100. bottom: 0;
  101. left: 0;
  102. right: 0;
  103. display: flex;
  104. justify-content: space-around;
  105. align-items: center;
  106. height: 160rpx;
  107. background-color: #ffffff;
  108. border-top: 1rpx solid #e5e5e5;
  109. z-index: 9999;
  110. .tabbar-item {
  111. flex: 1;
  112. display: flex;
  113. flex-direction: column;
  114. align-items: center;
  115. justify-content: center;
  116. padding: 10rpx 0;
  117. .icon-wrapper {
  118. width: 50rpx;
  119. height: 50rpx;
  120. display: flex;
  121. align-items: center;
  122. justify-content: center;
  123. .icon-img {
  124. width: 50rpx;
  125. height: 50rpx;
  126. }
  127. .back-top-icon {
  128. width: 50rpx;
  129. height: 50rpx;
  130. display: flex;
  131. align-items: center;
  132. justify-content: center;
  133. animation: bounce 0.5s ease-in-out;
  134. .icon-img {
  135. width: 50rpx;
  136. height: 50rpx;
  137. }
  138. }
  139. }
  140. .tabbar-text {
  141. font-size: 22rpx;
  142. color: #999999;
  143. margin-top: 6rpx;
  144. &.active {
  145. color: #F8C008;
  146. }
  147. }
  148. }
  149. }
  150. @keyframes bounce {
  151. 0%, 100% {
  152. transform: translateY(0);
  153. }
  154. 50% {
  155. transform: translateY(-5rpx);
  156. }
  157. }
  158. </style>