ms-tabs.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <template>
  2. <view class="tabBlock" v-if="type.length > 0">
  3. <scroll-view scroll-x="true" scroll-with-animation :scroll-left="tabsScrollLeft" @scroll="scroll">
  4. <view class="tab" id="tab_list">
  5. <view v-for="(item, index) in type"
  6. :key="index"
  7. :class="['tab__item', {'tab__item--active': currentIndex === index}]"
  8. :style="{color: (currentIndex === index ? `${itemColor}`: '')}"
  9. id="tab_item"
  10. @click="select(item, index)"
  11. >
  12. <view class="tab__item-title">
  13. {{item.title}}
  14. </view>
  15. </view>
  16. </view>
  17. <view class="tab__line"
  18. :style="{background: lineColor, width: lineStyle.width, transform: lineStyle.transform,transitionDuration: lineStyle.transitionDuration}">
  19. </view>
  20. </scroll-view>
  21. </view>
  22. </template>
  23. <script>
  24. export default {
  25. props: {
  26. value: [Number, String],
  27. type: { // 传值
  28. type: Array,
  29. default: ()=> {
  30. return []
  31. }
  32. },
  33. itemColor: String, // tab主色调
  34. lineColor: String ,// 下划线主色调
  35. lineAnimated: { // 是否展示下划线动画
  36. type: Boolean,
  37. default: true
  38. }
  39. },
  40. data() {
  41. return {
  42. currentIndex: 0,
  43. lineStyle: {},
  44. scrollLeft: 0,
  45. tabsScrollLeft: 0,
  46. duration: 0.3
  47. }
  48. },
  49. watch: {
  50. type() {
  51. this.setTabList()
  52. },
  53. value() {
  54. this.currentIndex = this.value
  55. this.setTabList()
  56. }
  57. },
  58. mounted() {
  59. this.currentIndex = this.value
  60. this.setTabList()
  61. if(!this.lineAnimated) {
  62. this.duration = 0
  63. }
  64. },
  65. methods: {
  66. select(item, index) {
  67. this.$emit('input', index)
  68. },
  69. setTabList() {
  70. this.$nextTick(()=>{
  71. if(this.type.length > 0) {
  72. this.setLine()
  73. this.scrollIntoView()
  74. }
  75. })
  76. },
  77. setLine() {
  78. let lineWidth = 0, lineLeft = 0
  79. this.getElementData(`#tab_item`, (data)=> {
  80. let el = data[this.currentIndex]
  81. lineWidth = el.width / 2
  82. // lineLeft = el.width * (this.currentIndex + 0.5) // 此种只能针对每个item长度一致的
  83. lineLeft = el.width / 2 + (-data[0].left) + el.left
  84. this.lineStyle = {
  85. width: `${lineWidth}px`,
  86. transform: `translateX(${lineLeft}px) translateX(-50%)`,
  87. transitionDuration: `${this.duration}s`
  88. };
  89. })
  90. },
  91. scrollIntoView() { // item滚动
  92. let lineLeft = 0;
  93. this.getElementData('#tab_list', (data)=> {
  94. let list = data[0]
  95. this.getElementData(`#tab_item`, (data)=> {
  96. let el = data[this.currentIndex]
  97. // lineLeft = el.width * (this.currentIndex + 0.5) - list.width / 2 - this.scrollLeft
  98. lineLeft = el.width / 2 + (-list.left) + el.left - list.width / 2 - this.scrollLeft
  99. this.tabsScrollLeft = this.scrollLeft + lineLeft
  100. })
  101. })
  102. },
  103. getElementData(el, callback){
  104. uni.createSelectorQuery().in(this).selectAll(el).boundingClientRect().exec((data) => {
  105. callback(data[0]);
  106. });
  107. },
  108. scroll(e) {
  109. this.scrollLeft = e.detail.scrollLeft;
  110. }
  111. }
  112. }
  113. </script>
  114. <style lang="scss">
  115. .tabBlock {
  116. position: relative;
  117. background: #fff;
  118. .tab {
  119. position: relative;
  120. display: flex;
  121. font-size: 28rpx;
  122. padding-bottom: 15rpx;
  123. white-space: nowrap;
  124. &__item {
  125. flex: 1;
  126. // width: 30%;
  127. text-align: center;
  128. line-height: 90rpx;
  129. color: $uni-text-color;
  130. &--active {
  131. color: $uni-color-primary;
  132. }
  133. &-title {
  134. margin: 0 40rpx;
  135. }
  136. }
  137. }
  138. .tab__line {
  139. display: block;
  140. height:6rpx;
  141. position: absolute;
  142. bottom: 15rpx;
  143. left: 0;
  144. z-index: 1;
  145. border-radius: 3rpx;
  146. position: relative;
  147. background: $uni-color-primary;
  148. }
  149. }
  150. </style>