custom-tabbar.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <template>
  2. <view class="custom-tabbar">
  3. <view
  4. class="tabbar-item"
  5. v-for="(item, index) in list"
  6. :key="index"
  7. @tap="switchTab(item.pagePath, index)"
  8. >
  9. <view class="tabbar-icon-container">
  10. <view
  11. v-if="item.pagePath === '/pages/message/message' && unreadMessageCount > 0"
  12. class="badge-div"
  13. >{{ unreadMessageCount }}</view>
  14. <image
  15. class="tabbar-icon"
  16. :src="activeIndex === index ? item.selectedIconPath : item.iconPath"
  17. mode="aspectFit"
  18. ></image>
  19. </view>
  20. <text
  21. class="tabbar-text"
  22. :style="{ color: activeIndex === index ? selectedColor : color }"
  23. >{{ item.text }}</text>
  24. </view>
  25. </view>
  26. </template>
  27. <script setup lang="js">
  28. import { ref, onMounted, computed } from 'vue';
  29. import { messageStore } from '../../store/message.js';
  30. const props = defineProps({
  31. activeIndex: {
  32. type: Number,
  33. default: 0
  34. }
  35. });
  36. const color = ref('#999999');
  37. const selectedColor = ref('#1F6CFF');
  38. const unreadMessageCount = computed(() => messageStore.unreadCount);
  39. // Mock data: In a real scenario, this could be fetched from an API
  40. const list = ref([
  41. {
  42. pagePath: '/pages/jobs/jobs',
  43. iconPath: '/static/tabbar/jobs_n.png',
  44. selectedIconPath: '/static/tabbar/jobs_a.png',
  45. text: '岗位'
  46. },
  47. {
  48. pagePath: '/pages/assessment/assessment',
  49. iconPath: '/static/tabbar/assess_n.png',
  50. selectedIconPath: '/static/tabbar/assess_a.png',
  51. text: '测评'
  52. },
  53. {
  54. pagePath: '/pages/message/message',
  55. iconPath: '/static/tabbar/msg_n.png',
  56. selectedIconPath: '/static/tabbar/msg_a.png',
  57. text: '消息'
  58. },
  59. {
  60. pagePath: '/pages/my/my',
  61. iconPath: '/static/tabbar/my_n.png',
  62. selectedIconPath: '/static/tabbar/my_a.png',
  63. text: '我的'
  64. }
  65. ]);
  66. const switchTab = (path, index) => {
  67. if (props.activeIndex !== index) {
  68. uni.switchTab({
  69. url: path
  70. });
  71. }
  72. };
  73. onMounted(() => {
  74. uni.hideTabBar({
  75. animation: false
  76. });
  77. });
  78. </script>
  79. <style lang="scss" scoped>
  80. .custom-tabbar {
  81. position: fixed;
  82. bottom: 0;
  83. left: 0;
  84. width: 100%;
  85. height: 100rpx;
  86. background-color: #FFFFFF;
  87. display: flex;
  88. justify-content: space-around;
  89. align-items: center;
  90. box-shadow: 0 -1rpx 10rpx rgba(0, 0, 0, 0.05);
  91. z-index: 999;
  92. padding-bottom: env(safe-area-inset-bottom);
  93. .tabbar-item {
  94. flex: 1;
  95. display: flex;
  96. flex-direction: column;
  97. justify-content: center;
  98. align-items: center;
  99. height: 100%;
  100. .tabbar-icon-container {
  101. position: relative;
  102. width: 48rpx;
  103. height: 48rpx;
  104. margin-bottom: 4rpx;
  105. .tabbar-icon {
  106. width: 100%;
  107. height: 100%;
  108. }
  109. .badge {
  110. position: absolute;
  111. top: -6rpx;
  112. right: -10rpx;
  113. width: 28rpx;
  114. height: 28rpx;
  115. background-color: #FF3B30;
  116. border-radius: 50%;
  117. border: 2rpx solid #FFF;
  118. z-index: 10;
  119. flex-shrink: 0;
  120. // Since user wants an 11 inside badge, let's just make it red bubble with hardcoded ::after for text
  121. &::after {
  122. content: "11";
  123. position: absolute;
  124. top: 50%;
  125. left: 50%;
  126. transform: translate(-50%, -50%) scale(0.8);
  127. color: white;
  128. font-size: 20rpx;
  129. font-weight: bold;
  130. }
  131. }
  132. }
  133. .tabbar-text {
  134. font-size: 20rpx;
  135. line-height: 1;
  136. }
  137. }
  138. }
  139. // Ensure the badge with "11" style is correctly scoped or use a normal div for badge
  140. .badge-div {
  141. position: absolute;
  142. top: -6rpx;
  143. right: -14rpx;
  144. min-width: 32rpx;
  145. height: 32rpx;
  146. background-color: #FF2B2B;
  147. border-radius: 16rpx;
  148. color: #FFF;
  149. font-size: 20rpx;
  150. font-weight: bold;
  151. display: flex;
  152. align-items: center;
  153. justify-content: center;
  154. box-sizing: border-box;
  155. padding: 0 4rpx;
  156. border: 2rpx solid #FFFFFF;
  157. }
  158. </style>