tui-tabs.vue 6.2 KB

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