tn-scroll-list.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <template>
  2. <view class="tn-scroll-list-class tn-scroll-list">
  3. <scroll-view
  4. class="tn-scroll-list__scroll-view"
  5. scroll-x
  6. :upper-threshold="0"
  7. :lower-threshold="0"
  8. @scroll="scrollHandler"
  9. @scrolltoupper="scrollToUpperHandler"
  10. @scrolltolower="scrollToLowerHandler"
  11. >
  12. <view class="tn-scroll-list__scroll-view__content">
  13. <slot></slot>
  14. </view>
  15. </scroll-view>
  16. <!-- 指示器-->
  17. <view
  18. v-if="indicator"
  19. class="tn-scroll-list__indicator"
  20. :style="[indicatorStyle]"
  21. >
  22. <view class="tn-scroll-list__indicator__line" :style="[lineStyle]">
  23. <view class="tn-scroll-list__indicator__line__bar" :style="[barStyle]"></view>
  24. </view>
  25. </view>
  26. </view>
  27. </template>
  28. <script>
  29. export default {
  30. name: 'tn-scroll-list',
  31. props: {
  32. // 是否显示指示器
  33. indicator: {
  34. type: Boolean,
  35. default: true
  36. },
  37. // 指示器整体宽度
  38. indicatorWidth: {
  39. type: [String, Number],
  40. default: 50
  41. },
  42. // 指示器滑块的宽度
  43. indicatorBarWidth: {
  44. type: [String, Number],
  45. default: 20
  46. },
  47. // 指示器颜色
  48. indicatorColor: {
  49. type: String,
  50. default: '#E6E6E6'
  51. },
  52. // 指示器激活时颜色
  53. indicatorActiveColor: {
  54. type: String,
  55. default: '#01BEFF'
  56. },
  57. // 自定义指示器样式
  58. indicatorStyle: {
  59. type: Object,
  60. default() {
  61. return {}
  62. }
  63. }
  64. },
  65. computed: {
  66. // 指示器滑块样式
  67. barStyle() {
  68. let style = {}
  69. // 获取滑动距离的比值
  70. // 滑块当前移动距离与总需滑动距离(指示器的总宽度减去滑块宽度)的比值 = scroll-view的滚动距离与目标滚动距离(scroll-view的实际宽度减去包裹元素的宽度)之比
  71. const scrollLeft = this.scrollInfo.scrollLeft,
  72. scrollWidth = this.scrollInfo.scrollWidth,
  73. barAllMoveWidth = uni.upx2px(this.indicatorWidth) - uni.upx2px(this.indicatorBarWidth);
  74. const x = scrollLeft / (scrollWidth - this.scrollWidth) * barAllMoveWidth
  75. style.transform = `translateX(${x}px)`
  76. // 设置滑块的宽度和背景颜色
  77. style.width = `${this.indicatorBarWidth}rpx`
  78. style.backgroundColor = this.indicatorActiveColor
  79. return style
  80. },
  81. // 指示器整体样式
  82. lineStyle() {
  83. let style = {}
  84. style.width = `${this.indicatorWidth}rpx`
  85. style.backgroundColor = this.indicatorColor
  86. return style
  87. }
  88. },
  89. data() {
  90. return {
  91. // 滑动时滑块信息
  92. scrollInfo: {
  93. scrollLeft: 0,
  94. scrollWidth: 0
  95. },
  96. // 滑动区域的宽度
  97. scrollWidth: 0
  98. }
  99. },
  100. mounted() {
  101. this.$nextTick(() => {
  102. this.init()
  103. })
  104. },
  105. methods: {
  106. // 初始化
  107. init() {
  108. this.getComponentWidth()
  109. },
  110. // 处理滚动事件
  111. scrollHandler(event) {
  112. this.scrollInfo = event.detail
  113. },
  114. // 滚动到最左边触发事件
  115. scrollToUpperHandler() {
  116. this.$emit('left')
  117. this.scrollInfo.scrollLeft = 0
  118. },
  119. // 滚动到最右边触发事件
  120. scrollToLowerHandler() {
  121. this.$emit('right')
  122. // this.scrollInfo.scrollLeft = uni.upx2px(this.indicatorWidth) - uni.upx2px(this.indicatorBarWidth)
  123. },
  124. // 获取组件的宽度
  125. getComponentWidth() {
  126. this._tGetRect('.tn-scroll-list').then(res => {
  127. if (!res) {
  128. setTimeout(() => {
  129. this.getComponentWidth()
  130. }, 10)
  131. return
  132. }
  133. this.scrollWidth = res.width
  134. })
  135. }
  136. }
  137. }
  138. </script>
  139. <style lang="scss" scoped>
  140. .tn-scroll-list {
  141. padding-bottom: 20rpx;
  142. &__scroll-view {
  143. display: flex;
  144. flex-direction: row;
  145. &__content {
  146. display: flex;
  147. flex-direction: row;
  148. }
  149. }
  150. &__indicator {
  151. display: flex;
  152. flex-direction: row;
  153. justify-content: center;
  154. margin-top: 30rpx;
  155. &__line {
  156. width: 120rpx;
  157. height: 8rpx;
  158. border-radius: 200rpx;
  159. overflow: hidden;
  160. &__bar {
  161. width: 40rpx;
  162. height: 8rpx;
  163. border-radius: 200rpx;
  164. }
  165. }
  166. }
  167. }
  168. </style>