index.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <script setup lang="ts">
  2. // i-carbon-code
  3. import type { CustomTabBarItem } from './types'
  4. import { useLoadingStore } from '@/store/loading'
  5. import { customTabbarEnable, needHideNativeTabbar, tabbarCacheEnable } from './config'
  6. import { tabbarList, tabbarStore } from './store'
  7. // #ifdef MP-WEIXIN
  8. // 将自定义节点设置成虚拟的(去掉自定义组件包裹层),更加接近Vue组件的表现,能更好的使用flex属性
  9. defineOptions({
  10. virtualHost: true,
  11. })
  12. // #endif
  13. const loadingStore = useLoadingStore()
  14. /**
  15. * 中间的鼓包tabbarItem的点击事件
  16. */
  17. function handleClickBulge() {
  18. uni.showToast({
  19. title: '点击了中间的鼓包tabbarItem',
  20. icon: 'none',
  21. })
  22. }
  23. function handleClick(index: number) {
  24. // 点击原来的不做操作
  25. if (index === tabbarStore.curIdx) {
  26. return
  27. }
  28. // 显示加载页
  29. loadingStore.showLoading('切换页面中...')
  30. if (tabbarList[index].isBulge) {
  31. handleClickBulge()
  32. return
  33. }
  34. const url = tabbarList[index].pagePath
  35. tabbarStore.setCurIdx(index)
  36. if (tabbarCacheEnable) {
  37. uni.switchTab({
  38. url,
  39. complete: () => {
  40. // 切换完成后隐藏加载页
  41. loadingStore.hideLoading()
  42. }
  43. })
  44. }
  45. else {
  46. uni.navigateTo({
  47. url,
  48. complete: () => {
  49. // 切换完成后隐藏加载页
  50. loadingStore.hideLoading()
  51. }
  52. })
  53. }
  54. }
  55. // #ifndef MP-WEIXIN || MP-ALIPAY
  56. // 因为有了 custom:true, 微信里面不需要多余的hide操作
  57. onLoad(() => {
  58. // 解决原生 tabBar 未隐藏导致有2个 tabBar 的问题
  59. needHideNativeTabbar
  60. && uni.hideTabBar({
  61. fail(err) {
  62. console.log('hideTabBar fail: ', err)
  63. },
  64. success(res) {
  65. // console.log('hideTabBar success: ', res)
  66. },
  67. })
  68. })
  69. // #endif
  70. // #ifdef MP-ALIPAY
  71. onMounted(() => {
  72. // 解决支付宝自定义tabbar 未隐藏导致有2个 tabBar 的问题; 注意支付宝很特别,需要在 onMounted 钩子调用
  73. customTabbarEnable // 另外,支付宝里面,只要是 customTabbar 都需要隐藏
  74. && uni.hideTabBar({
  75. fail(err) {
  76. console.log('hideTabBar fail: ', err)
  77. },
  78. success(res) {
  79. // console.log('hideTabBar success: ', res)
  80. },
  81. })
  82. })
  83. // #endif
  84. const activeColor = 'var(--wot-color-theme, #FF654F )'
  85. const inactiveColor = '#888888'
  86. function getColorByIndex(index: number) {
  87. return tabbarStore.curIdx === index ? activeColor : inactiveColor
  88. }
  89. function getImageByIndex(index: number, item: CustomTabBarItem) {
  90. if (!item.iconActive) {
  91. console.warn('image 模式下,需要配置 iconActive (高亮时的图片),否则无法切换高亮图片')
  92. return item.icon
  93. }
  94. return tabbarStore.curIdx === index ? item.iconActive : item.icon
  95. }
  96. </script>
  97. <template>
  98. <view v-if="customTabbarEnable" class="h-100rpx pb-safe">
  99. <view class="border-and-fixed bg-white" @touchmove.stop.prevent>
  100. <view class="h-100rpx flex items-center pt-1">
  101. <view v-for="(item, index) in tabbarList" :key="index"
  102. class="flex flex-1 flex-col items-center justify-center" :style="{ color: getColorByIndex(index) }"
  103. @click="handleClick(index)">
  104. <view v-if="item.isBulge" class="relative">
  105. <!-- 中间一个鼓包tabbarItem的处理 -->
  106. <view class="bulge">
  107. <!-- TODO 2/2: 中间鼓包tabbarItem配置:通常是一个图片,或者icon,点击触发业务逻辑 -->
  108. <!-- 常见的是:扫描按钮、发布按钮、更多按钮等 -->
  109. <image class="mt-6rpx h-200rpx w-200rpx" src="/static/tabbar/scan.png" />
  110. </view>
  111. </view>
  112. <view v-else class="relative px-3 text-center">
  113. <template v-if="item.iconType === 'uiLib'">
  114. <!-- TODO: 以下内容请根据选择的UI库自行替换 -->
  115. <!-- 如:<wd-icon name="home" /> (https://wot-design-uni.cn/component/icon.html) -->
  116. <!-- 如:<uv-icon name="home" /> (https://www.uvui.cn/components/icon.html) -->
  117. <!-- 如:<sar-icon name="image" /> (https://sard.wzt.zone/sard-uniapp-docs/components/icon)(sar没有home图标^_^) -->
  118. <!-- <wd-icon :name="item.icon" size="20" /> -->
  119. </template>
  120. <template v-if="item.iconType === 'unocss' || item.iconType === 'iconfont'">
  121. <view :class="item.icon" class="text-20px" />
  122. </template>
  123. <template v-if="item.iconType === 'image'">
  124. <image :src="getImageByIndex(index, item)" mode="scaleToFill" class="h-41rpx w-42rpx" />
  125. </template>
  126. <view class="mt-15rpx text-22rpx">
  127. {{ item.text }}
  128. </view>
  129. <!-- 角标显示 -->
  130. <view v-if="item.badge">
  131. <template v-if="item.badge === 'dot'">
  132. <view class="absolute right-0 top-0 h-2 w-2 rounded-full bg-#f56c6c" />
  133. </template>
  134. <template v-else>
  135. <view
  136. class="absolute top-0 box-border h-5 min-w-5 center rounded-full bg-#f56c6c px-1 text-center text-xs text-white -right-3">
  137. {{ item.badge > 99 ? '99+' : item.badge }}
  138. </view>
  139. </template>
  140. </view>
  141. </view>
  142. </view>
  143. </view>
  144. <view class="pb-safe" />
  145. </view>
  146. </view>
  147. </template>
  148. <style scoped lang="scss">
  149. .border-and-fixed {
  150. position: fixed;
  151. bottom: 0;
  152. left: 0;
  153. right: 0;
  154. z-index: 999;
  155. border-top: 1px solid #eee;
  156. box-sizing: border-box;
  157. }
  158. // 中间鼓包的样式
  159. .bulge {
  160. position: absolute;
  161. top: -20px;
  162. left: 50%;
  163. transform-origin: top center;
  164. transform: translateX(-50%) scale(0.5) translateY(-33%);
  165. display: flex;
  166. justify-content: center;
  167. align-items: center;
  168. width: 250rpx;
  169. height: 250rpx;
  170. border-radius: 50%;
  171. background-color: #fff;
  172. box-shadow: inset 0 0 0 1px #fefefe;
  173. &:active {
  174. // opacity: 0.8;
  175. }
  176. }
  177. </style>