tui-tabs.vue 5.6 KB

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