app-tabs.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <template>
  2. <view class="tab-box" id="tab-box" v-if="tabList.length > 0">
  3. <view class="horizontal">
  4. <scroll-view :scroll-x="true" style="white-space: nowrap; display: flex;" scroll-with-animation :scroll-left="slider.scrollLeft">
  5. <block v-for="(item, index) in tabList" :key="index" >
  6. <view class="item" :class="{ active: activeIndex === index }" :id="'tab_'+index" @click="tabClick(index)">{{ item.text || item.name}}</view>
  7. </block>
  8. <view class="underline" :style="'transform:translateX(' + slider.left + 'px);width:' + slider.width + 'px'"></view>
  9. </scroll-view>
  10. </view>
  11. </view>
  12. </template>
  13. <script>
  14. export default {
  15. name: 'liuyuno-tabs',
  16. props: {
  17. tabData: {
  18. type: Array,
  19. default: () => []
  20. },
  21. defaultIndex: {
  22. type: Number,
  23. default: 0
  24. },
  25. underLinePadding: {
  26. type: Number,
  27. default: 10
  28. },
  29. },
  30. data() {
  31. return {
  32. tabList: [],
  33. tabListSlider: [],
  34. box: {
  35. left: 0,
  36. right: 0,
  37. top: 0,
  38. width: 0,
  39. height: 0,
  40. bottom: 0,
  41. },
  42. slider: {
  43. left: 0,
  44. width: 0,
  45. scrollLeft: 0
  46. },
  47. activeIndex: 0
  48. };
  49. },
  50. watch: {
  51. tabData(value) {
  52. this.tabList = value;
  53. setTimeout(() => {
  54. this.updateTabWidth();
  55. }, 0);
  56. },
  57. },
  58. mounted() {
  59. this.tabList = this.tabData;
  60. this.activeIndex = this.defaultIndex;
  61. setTimeout(() => {
  62. const query = uni.createSelectorQuery().in(this);
  63. query.select('.tab-box').boundingClientRect((res) => {
  64. this.box = res;
  65. this.updateTabWidth();
  66. }).exec();
  67. }, 0);
  68. },
  69. methods: {
  70. tabClick(index) {
  71. this.activeIndex = index;
  72. this.tabToIndex(index);
  73. this.$emit('tabClick', index);
  74. },
  75. tabToIndex(index) {
  76. let _slider = this.tabListSlider[index];
  77. this.slider = {
  78. left: _slider.left + this.underLinePadding,
  79. width: _slider.width - this.underLinePadding * 2,
  80. scrollLeft: _slider.scrollLeft,
  81. }
  82. },
  83. updateTabWidth(index = 0) {
  84. let data = this.tabList;
  85. if (data.length == 0) return false;
  86. const query = uni.createSelectorQuery().in(this);
  87. query.select('#tab_' + index).boundingClientRect((res) => {
  88. let _prev_slider = this.tabListSlider[index - 1];
  89. this.tabListSlider[index] = {
  90. left: res.left - this.box.left,
  91. width: res.width,
  92. scrollLeft: res.left - this.box.left - (_prev_slider ? _prev_slider.width : 0),
  93. }
  94. if (this.activeIndex == index) {
  95. this.tabToIndex(this.activeIndex);
  96. }
  97. index++;
  98. if (data.length > index) {
  99. this.updateTabWidth(index);
  100. }
  101. }).exec();
  102. }
  103. }
  104. }
  105. </script>
  106. <style lang="less">
  107. .tab-box {
  108. width: 100%;
  109. color: rgba(0, 0, 0, 0.8);
  110. display: flex;
  111. height: 90upx;
  112. background: #fff;
  113. font-size: 28upx;
  114. box-shadow: 0 1px 5px rgba(0, 0, 0, 0.06);
  115. position: relative;
  116. z-index: 10;
  117. overflow: hidden;
  118. .active {
  119. color: #e54d42;
  120. }
  121. .horizontal {
  122. width: 100%;
  123. .item {
  124. display: inline-block;
  125. text-align: center;
  126. padding: 0 30upx;
  127. height: 86upx;
  128. line-height: 90upx;
  129. }
  130. .underline {
  131. height: 4upx;
  132. background-color: #e54d42;
  133. border-radius: 3px;
  134. transition: .5s;
  135. }
  136. }
  137. }
  138. </style>