You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

161 lines
3.7 KiB

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