tui-tabs.vue 6.1 KB

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