tui-tabbar.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <template>
  2. <view class="gui-tabbar-container" :style="{'---height':!hump?'100rpx':'160rpx'}">
  3. <view class="gui-tabbar"
  4. :class="{ 'gui-tabbar-fixed': isFixed }"
  5. :style="{ background: backgroundColor }">
  6. <block v-for="(item, index) in tabBar" :key="index">
  7. <view class="gui-tabbar-item" :class="{ 'gui-item-hump': item.hump }"
  8. :style="{ backgroundColor: item.hump ? backgroundColor : 'none' }"
  9. @tap="tabbarSwitch(index, item.hump, item.pagePath, item.verify)">
  10. <view class="gui-icon-box" :class="{ 'gui-tabbar-hump': item.hump }">
  11. <image class="img"
  12. :src="String(current) == String(index) ? appData.imgUrl+item.selectedIconPath : appData.imgUrl+item.iconPath"
  13. :class="[item.hump ? '' : 'gui-tabbar-icon']"></image>
  14. <view :class="[item.isDot ? 'gui-badge-dot' : 'gui-badge']"
  15. :style="{ color: badgeColor, backgroundColor: badgeBgColor }" v-if="item.num">
  16. {{ item.isDot ? '' : item.num }}
  17. </view>
  18. </view>
  19. <view class="gui-text-scale" :class="{ 'gui-text-hump': item.hump }"
  20. :style="{ color: String(current) == String(index) ? selectedColor : color }">{{ item.text }}
  21. </view>
  22. </view>
  23. </block>
  24. <view :style="{ background: backgroundColor }" :class="{ 'gui-hump-box': hump}"
  25. v-if="hump"></view>
  26. </view>
  27. <view class="page-floor"></view>
  28. </view>
  29. </template>
  30. <script>
  31. let App = getApp()
  32. import mixinsPage from "@/common/mixins-model.js"
  33. export default {
  34. mixins: [mixinsPage],
  35. components: {},
  36. data() {
  37. return {}
  38. },
  39. props: {
  40. value: {
  41. type: [String, Number, Object],
  42. default: null
  43. },
  44. //当前索引
  45. current: {
  46. type: [Number, String],
  47. default: 0
  48. },
  49. //字体颜色
  50. color: {
  51. type: String,
  52. default: '#888888'
  53. },
  54. //字体选中颜色
  55. selectedColor: {
  56. type: String,
  57. default: '#333'
  58. },
  59. //背景颜色
  60. backgroundColor: {
  61. type: String,
  62. default: '#FFFFFF'
  63. },
  64. //是否需要中间凸起按钮
  65. hump: {
  66. type: Boolean,
  67. default: true
  68. },
  69. //固定在底部
  70. isFixed: {
  71. type: Boolean,
  72. default: true
  73. },
  74. //角标字体颜色
  75. badgeColor: {
  76. type: String,
  77. default: '#fff'
  78. },
  79. //角标背景颜色
  80. badgeBgColor: {
  81. type: String,
  82. default: '#F74D54'
  83. },
  84. //tabbar
  85. // "pagePath": "/pages/my/my", 页面路径
  86. // "text": "thor", 标题
  87. // "iconPath": "thor_gray.png", 图标地址
  88. // "selectedIconPath": "thor_active.png", 选中图标地址
  89. // "hump": true, 是否为凸起图标
  90. // "num": 2, 角标数量
  91. // "isDot": true, 角标是否为圆点
  92. // "verify": true 是否验证 (如登录)
  93. tabBar: {
  94. type: Array,
  95. default () {
  96. return [];
  97. }
  98. }
  99. },
  100. watch: {
  101. value: {
  102. handler(nval, oval) {},
  103. immediate: true,
  104. deep: true
  105. }
  106. },
  107. created() {
  108. this.appData = App.globalData ? App.globalData : getApp().globalData;
  109. },
  110. methods: {
  111. tabbarSwitch(index, hump, pagePath, verify) {
  112. if (verify && !this.$api.isLogin(true)) {
  113. return false
  114. }
  115. // console.log(pagePath, index, this.current)
  116. if (pagePath && index != this.current) {
  117. this.$api.href(pagePath)
  118. return false
  119. }
  120. this.$emit('click', {
  121. index: index,
  122. hump: hump,
  123. pagePath: pagePath,
  124. verify: verify
  125. });
  126. }
  127. }
  128. }
  129. </script>
  130. <style lang="scss" scoped>
  131. .gui-tabbar-container {
  132. width: 100%;
  133. height: var(---height);
  134. height: calc(constant(safe-area-inset-bottom) + var(---height));
  135. height: calc(env(safe-area-inset-bottom) + var(---height));
  136. position: relative;
  137. }
  138. .gui-tabbar {
  139. width: 100%;
  140. height: 100rpx;
  141. display: flex;
  142. align-items: center;
  143. justify-content: space-between;
  144. position: relative;
  145. &::before {
  146. content: ' ';
  147. width: 100%;
  148. border-top: 1px solid #eeeeee;
  149. position: absolute;
  150. top: 0;
  151. left: 0;
  152. transform: scaleY(0.5) translateZ(0);
  153. transform-origin: 0 0;
  154. display: block;
  155. z-index: 3;
  156. }
  157. &.gui-tabbar-fixed {
  158. position: fixed;
  159. z-index: 66;
  160. left: 0;
  161. bottom: 0;
  162. padding-bottom: constant(safe-area-inset-bottom);
  163. padding-bottom: env(safe-area-inset-bottom);
  164. box-sizing: content-box !important;
  165. }
  166. .gui-tabbar-item {
  167. height: 100%;
  168. flex: 1;
  169. display: flex;
  170. text-align: center;
  171. align-items: center;
  172. flex-direction: column;
  173. justify-content: space-between;
  174. position: relative;
  175. padding: 10rpx 0;
  176. box-sizing: border-box;
  177. z-index: 5;
  178. }
  179. .gui-icon-box {
  180. position: relative;
  181. }
  182. .gui-item-hump {
  183. height: 98rpx;
  184. }
  185. .gui-tabbar-icon {
  186. width: 52rpx;
  187. height: 52rpx;
  188. display: block;
  189. }
  190. .gui-hump-box {
  191. width: 120rpx;
  192. height: 120rpx;
  193. position: absolute;
  194. left: 50%;
  195. transform: translateX(-50%);
  196. top: -50rpx;
  197. border-radius: 50%;
  198. z-index: 4;
  199. }
  200. .gui-hump-box::after {
  201. content: ' ';
  202. height: 200%;
  203. width: 200%;
  204. border: 1px solid #eeeeee;
  205. position: absolute;
  206. top: 0;
  207. left: 0;
  208. transform: scale(0.5) translateZ(0);
  209. transform-origin: 0 0;
  210. border-radius: 120rpx;
  211. box-sizing: border-box;
  212. display: block;
  213. }
  214. .gui-tabbar-hump {
  215. width: 100rpx;
  216. height: 100rpx;
  217. position: absolute;
  218. left: 50%;
  219. -webkit-transform: translateX(-50%) rotate(0deg);
  220. transform: translateX(-50%) rotate(0deg);
  221. top: -40rpx;
  222. -webkit-transition: all 0.2s linear;
  223. transition: all 0.2s linear;
  224. border-radius: 50%;
  225. z-index: 5;
  226. }
  227. .gui-tabbar-hump .img {
  228. width: 100rpx;
  229. height: 100rpx;
  230. display: block;
  231. }
  232. .gui-hump-active {
  233. -webkit-transform: translateX(-50%) rotate(135deg);
  234. transform: translateX(-50%) rotate(135deg);
  235. }
  236. .gui-text-scale {
  237. font-weight: bold;
  238. transform: scale(0.8);
  239. font-size: 25rpx;
  240. line-height: 28rpx;
  241. transform-origin: center 100%;
  242. }
  243. .gui-text-hump {
  244. position: absolute;
  245. left: 50%;
  246. bottom: 10rpx;
  247. transform: scale(0.8) translateX(-50%);
  248. transform-origin: 0 100%;
  249. }
  250. .gui-badge {
  251. position: absolute;
  252. font-size: 24rpx;
  253. height: 32rpx;
  254. min-width: 20rpx;
  255. padding: 0 6rpx;
  256. border-radius: 40rpx;
  257. right: 0;
  258. top: -5rpx;
  259. transform: translateX(70%);
  260. display: flex;
  261. align-items: center;
  262. justify-content: center;
  263. }
  264. .gui-badge-dot {
  265. position: absolute;
  266. height: 16rpx;
  267. width: 16rpx;
  268. border-radius: 50%;
  269. right: -4rpx;
  270. top: -4rpx;
  271. }
  272. .gui-header-icon {
  273. width: 100%;
  274. position: fixed;
  275. top: 0;
  276. padding: 0 12rpx;
  277. display: flex;
  278. align-items: center;
  279. height: 32px;
  280. transform: translateZ(0);
  281. z-index: 67;
  282. box-sizing: border-box;
  283. }
  284. }
  285. </style>