custom-tab-bar.uvue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <template>
  2. <view class="tabs">
  3. <view ref="tabview" class="tab-view">
  4. <!-- 注意tab的逻辑是:第一次使用v-if创建,创建之后不再使用v-if,而是设置visibility来隐藏和显示。不能设置tab的v-if为false,因为销毁再创建影响性能 -->
  5. <tab1 ref="tab1" class="tab-page" v-if="tabList[0].init" :style="{visibility:(selectedIndex==0?'visible':'hidden')}"></tab1>
  6. <tab2 ref="tab2" class="tab-page" v-if="tabList[1].init" :style="{visibility:(selectedIndex==1?'visible':'hidden')}"></tab2>
  7. </view>
  8. <view ref="tabbar" class="tab-bar">
  9. <view class="tab-item" @click="onTabClick(0)">
  10. <view ref="tab-item1" class="tab-item-content">
  11. <text v-if="displayArrow" class="tab-item-icon tab-item-arrow uni-icon"
  12. :class="selectedIndex==0 ? 'tab-item-text-active' : ''">
  13. {{'\ue6bd'}}
  14. </text>
  15. <text v-if="!displayArrow" class="tab-item-icon uni-icon"
  16. :class="selectedIndex==0 ? 'tab-item-text-active' : ''">{{'\ue644'}}</text>
  17. <text v-if="!displayArrow" class="tab-item-text" :class="selectedIndex==0 ? 'tab-item-text-active' : ''">
  18. 首页
  19. </text>
  20. </view>
  21. </view>
  22. <view>
  23. <image class="concave-image" mode="heightFix" src="/static/template/custom-tab-bar/concave.png"></image>
  24. </view>
  25. <view class="tab-item" @click="onTabClick(1)">
  26. <view ref="tab-item2" class="tab-item-content">
  27. <text class="tab-item-icon uni-icon"
  28. :class="selectedIndex==1 ? 'tab-item-text-active' : ''">{{'\ue699'}}</text>
  29. <text class="tab-item-text" :class="selectedIndex==1 ? 'tab-item-text-active' : ''">
  30. 我的
  31. </text>
  32. </view>
  33. </view>
  34. </view>
  35. <view class="btn-plus" @click="onPlusClick">
  36. <text class="btn-plus-text">+</text>
  37. </view>
  38. </view>
  39. </template>
  40. <script>
  41. import tab1 from './custom-tab-bar-tab1.uvue';
  42. import tab2 from './custom-tab-bar-tab2.uvue';
  43. type TabItem = {
  44. init : boolean,
  45. preload : boolean,
  46. }
  47. export default {
  48. components: {
  49. tab1,
  50. tab2
  51. },
  52. data() {
  53. return {
  54. tabList: [
  55. {
  56. init: true,
  57. preload: false
  58. } as TabItem,
  59. {
  60. init: false,
  61. preload: false
  62. } as TabItem,
  63. ] as TabItem[],
  64. selectedIndex: 0,
  65. displayArrow: false,
  66. lastTab1Top:0,
  67. tabViewHeight: 0
  68. }
  69. },
  70. onLoad() {
  71. uni.$on('tabchange', this.onTabPageEvent) //监听tab1页面发出的tabchange事件,触发到本页面的onTabPageEvent方法。为了判断tab1的scroll-view滚动距离
  72. },
  73. onReady() {
  74. // this.setSelectedIndex(0)
  75. (this.$refs["tabview"] as UniElement).getBoundingClientRectAsync()!.then((res: DOMRect) => {
  76. this.tabViewHeight = res.height
  77. });
  78. },
  79. onUnload() {
  80. uni.$off('tabchange', this.onTabPageEvent)
  81. },
  82. methods: {
  83. onTabClick(index : number) {
  84. if (this.selectedIndex == index && index == 0 && this.displayArrow == true) { //首页当tab按钮变成向上时,点向上就滚动到顶
  85. // console.log("11");
  86. this.displayArrow = false;
  87. (this.$refs["tab1"]! as ComponentPublicInstance).$callMethod('scrollTop', 0)
  88. }
  89. else if (index !=0){ //不在首页时,把箭头变成图标
  90. // console.log("22");
  91. this.displayArrow = false
  92. }
  93. else if (index == 0 && this.selectedIndex !=0){ //从其他tab切回首页时,检查是否需要把图标变箭头
  94. // console.log("33",this.lastTab1Top, this.tabViewHeight);
  95. this.displayArrow = this.lastTab1Top > this.tabViewHeight
  96. }
  97. this.setSelectedIndex(index);
  98. // console.log('index: ',index);
  99. // console.log('this.selectedIndex: ',this.selectedIndex);
  100. // console.log('this.displayArrow: ',this.displayArrow);
  101. // console.log('this.lastTab1Top: ',this.lastTab1Top);
  102. },
  103. onTabPageEvent(top : number) {
  104. // console.log('top: ',top);
  105. this.displayArrow = top > this.tabViewHeight //滚动1屏后,就把第一个tab的图标从首页变成向上箭头
  106. this.lastTab1Top = top
  107. },
  108. setSelectedIndex(index : number) {
  109. if (this.selectedIndex === index) {
  110. return
  111. }
  112. if (!this.tabList[index].init) {
  113. this.tabList[index].init = true
  114. }
  115. this.selectedIndex = index
  116. },
  117. onPlusClick() {
  118. uni.showModal({
  119. title: "提示",
  120. content: "你点击了 +",
  121. showCancel: false
  122. })
  123. }
  124. }
  125. }
  126. </script>
  127. <style>
  128. @font-face {
  129. font-family: "UniIcon";
  130. src: url('@/static/fonts/uni-icon.ttf');
  131. }
  132. .uni-icon {
  133. font-family: "UniIcon";
  134. font-size: 16px;
  135. font-style: normal;
  136. }
  137. .tabs {
  138. flex: 1;
  139. background-color: #fff;
  140. overflow: visible;
  141. }
  142. .tab-view {
  143. flex: 1;
  144. }
  145. .tab-page {
  146. position: absolute;
  147. width: 100%;
  148. height: 100%;
  149. }
  150. .tab-bar {
  151. flex-direction: row;
  152. height: 56px;
  153. overflow: visible;
  154. }
  155. .tab-item {
  156. flex: 1;
  157. position: relative;
  158. background-color: #1e90ff;
  159. overflow: visible;
  160. }
  161. .tab-item-content {
  162. margin: auto;
  163. transition: transform 0.3s;
  164. }
  165. .tab-item-icon {
  166. color: #ccc;
  167. font-size: 12px;
  168. text-align: center;
  169. margin-bottom: 4px;
  170. }
  171. .tab-item-text {
  172. color: #ccc;
  173. font-size: 12px;
  174. text-align: center;
  175. }
  176. .tab-item-text-active {
  177. color: #fff;
  178. }
  179. .tab-item-arrow {
  180. font-size: 30px !important;
  181. font-weight: bold;
  182. }
  183. .concave-image {
  184. height: 56px;
  185. }
  186. .btn-plus {
  187. position: absolute;
  188. width: 70px;
  189. height: 70px;
  190. bottom: 21px;
  191. border-radius: 50px;
  192. background-color: #FE5722;
  193. box-shadow: 0 0 4px rgba(0, 0, 0, 0.5);
  194. align-self: center;
  195. align-items: center;
  196. justify-content: center;
  197. overflow: visible;
  198. }
  199. .btn-plus-text {
  200. color: #fff;
  201. font-size: 32px;
  202. }
  203. </style>