tabs.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <template>
  2. <view class="tui-tabs-view" :class="[isFixed?'tui-tabs-fixed':'tui-tabs-relative',unlined?'tui-unlined':'']" :style="{height:height+'rpx',padding:`0 ${padding}rpx`,background:bgColor,top:isFixed?top+'px':'auto'}">
  3. <view v-for="(item,index) in tabs" :key="index" class="tui-tabs-item" :class="{'border-left': borderLeft}" :style="{width:itemWidth}" @tap.stop="swichTabs(index)">
  4. <view class="tui-tabs-title" :class="{'tui-tabs-active':currentTab==index,'tui-tabs-disabled':item.disabled}" :style="{color:currentTab==index?selectedColor:color,fontSize:size+'rpx',lineHeight:size+'rpx',fontWeight:bold && currentTab==index?'bold':'normal'}">{{item.name}}</view>
  5. <div v-if="item.value">{{ item.value }}</div>
  6. </view>
  7. <view class="tui-tabs-slider" :style="{transform:'translateX('+scrollLeft+'px)',width:sliderWidth+'rpx',height:
  8. sliderHeight+'rpx',borderRadius:sliderRadius,bottom:bottom,background:sliderBgColor,marginBottom:bottom=='50%'?('-'+sliderHeight/2+'rpx'):0}"></view>
  9. </view>
  10. </template>
  11. <script>
  12. export default {
  13. name: 'tuiTabs',
  14. props: {
  15. // 标签页
  16. tabs: {
  17. type: Array,
  18. default() {
  19. return []
  20. }
  21. },
  22. // rpx
  23. height: {
  24. type: Number,
  25. default: 80
  26. },
  27. // rpx 只对左右padding起作用,上下为0
  28. padding: {
  29. type: Number,
  30. default: 30
  31. },
  32. // 背景色
  33. bgColor: {
  34. type: String,
  35. default: '#FFFFFF'
  36. },
  37. // 是否固定
  38. isFixed: {
  39. type: Boolean,
  40. default: false
  41. },
  42. // px
  43. top: {
  44. type: Number, // #ifndef H5
  45. default: 0, // #endif
  46. // #ifdef H5
  47. default: 0
  48. // #endif
  49. },
  50. // 是否去掉底部线条
  51. unlined: {
  52. type: Boolean,
  53. default: false
  54. },
  55. // 当前选项卡
  56. currentTab: {
  57. type: Number,
  58. default: 0
  59. },
  60. // 滑块宽度
  61. sliderWidth: {
  62. type: Number,
  63. default: 68
  64. },
  65. // 滑块高度
  66. sliderHeight: {
  67. type: Number,
  68. default: 6
  69. },
  70. // 滑块背景颜色
  71. sliderBgColor: {
  72. type: String,
  73. default: '#FF2842'
  74. },
  75. sliderRadius: {
  76. type: String,
  77. default: '50rpx'
  78. },
  79. // 滑块bottom
  80. bottom: {
  81. type: String,
  82. default: '0'
  83. },
  84. // 标签页宽度
  85. itemWidth: {
  86. type: String,
  87. default: '25%'
  88. },
  89. // 字体颜色
  90. color: {
  91. type: String,
  92. default: '#999'
  93. },
  94. // 选中后字体颜色
  95. selectedColor: {
  96. type: String,
  97. default: '#FF2842'
  98. },
  99. // 字体大小
  100. size: {
  101. type: Number,
  102. default: 28
  103. },
  104. // 选中后 是否加粗 ,未选中则无效
  105. bold: {
  106. type: Boolean,
  107. default: false
  108. },
  109. // 是否显示borer-right
  110. borderLeft: {
  111. type: Boolean,
  112. default: false
  113. }
  114. },
  115. watch: {
  116. currentTab() {
  117. this.checkCor()
  118. }
  119. },
  120. created() {
  121. setTimeout(() => {
  122. // 高度自适应
  123. uni.getSystemInfo({
  124. success: res => {
  125. this.winWidth = res.windowWidth
  126. this.checkCor()
  127. }
  128. })
  129. }, 50)
  130. },
  131. data() {
  132. return {
  133. winWidth: 0,
  134. scrollLeft: 0
  135. }
  136. },
  137. methods: {
  138. checkCor: function() {
  139. let tabsNum = this.tabs.length
  140. let padding = (this.winWidth / 750) * this.padding
  141. let width = this.winWidth - padding * 2
  142. let left = (width / tabsNum - (this.winWidth / 750) * this.sliderWidth) / 2 + padding
  143. let scrollLeft = left
  144. if (this.currentTab > 0) {
  145. scrollLeft = scrollLeft + (width / tabsNum) * this.currentTab
  146. }
  147. this.scrollLeft = scrollLeft
  148. },
  149. // 点击标题切换当前页时改变样式
  150. swichTabs: function(index) {
  151. let item = this.tabs[index]
  152. if (item && item.disabled) return
  153. if (this.currentTab == index) {
  154. return false
  155. } else {
  156. this.$emit('change', {
  157. index: Number(index)
  158. })
  159. }
  160. }
  161. }
  162. }
  163. </script>
  164. <style lang="scss" scoped>
  165. .tui-tabs-view {
  166. width: 100%;
  167. box-sizing: border-box;
  168. display: flex;
  169. align-items: center;
  170. justify-content: space-between;
  171. z-index: 99;
  172. box-shadow: 4px 4px 10px #eee;
  173. .tui-tabs-item {
  174. &.border-left {
  175. border-left: 2px solid #ddd;
  176. }
  177. }
  178. .tui-tabs-item:first-child {
  179. &.border-left {
  180. border-left: none;
  181. }
  182. }
  183. }
  184. .tui-tabs-relative {
  185. position: relative;
  186. }
  187. .tui-tabs-fixed {
  188. position: fixed;
  189. left: 0;
  190. }
  191. .tui-tabs-fixed::before,
  192. .tui-tabs-relative::before {
  193. content: '';
  194. position: absolute;
  195. border-bottom: 1upx solid #eaeef1;
  196. -webkit-transform: scaleY(0.5);
  197. transform: scaleY(0.5);
  198. bottom: 0;
  199. right: 0;
  200. left: 0;
  201. }
  202. .tui-unlined::before {
  203. border-bottom: 0 !important;
  204. }
  205. .tui-tabs-item {
  206. display: flex;
  207. align-items: center;
  208. justify-content: center;
  209. }
  210. .tui-tabs-disabled {
  211. opacity: 0.6;
  212. }
  213. .tui-tabs-title {
  214. display: flex;
  215. align-items: center;
  216. justify-content: center;
  217. position: relative;
  218. z-index: 2;
  219. }
  220. .tui-tabs-active {
  221. transition: all 0.15s ease-in-out;
  222. }
  223. .tui-tabs-slider {
  224. position: absolute;
  225. left: 0;
  226. transition: all 0.15s ease-in-out;
  227. z-index: 0;
  228. transform: translateZ(0);
  229. }
  230. </style>