fs-scroll-list.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. <template>
  2. <view class="fs-scroll-list">
  3. <scroll-view
  4. scroll-x
  5. :show-scrollbar="false"
  6. :lower-threshold="0"
  7. :upper-threshold="0"
  8. @scrolltoupper="handleToUpper"
  9. @scrolltolower="handleToLower"
  10. @scroll="handleScroll"
  11. >
  12. <view class="fs-scroll-list-content"><slot></slot></view>
  13. </scroll-view>
  14. <view class="fs-scroll-indicator" v-if="indicator">
  15. <view class="fs-scroll-indicator-line"><view class="fs-scroll-indicator-bar" :style="barStyle"></view></view>
  16. </view>
  17. </view>
  18. </template>
  19. <script>
  20. /**
  21. * 滚动列表组件
  22. * @description 滚动列表组件
  23. * @property {Boolean} indicator 是否显示面板指示器
  24. * @property {String} indicatorColor 指示器背景颜色
  25. * @property {String} indicatorActiveColor 指示器滑块颜色
  26. * @property {String} indicatorWidth 指示器的整体宽度(传值的时候需要带单位px)
  27. * @property {String} indicatorBarWidth 滑块的宽度(传值的时候需要带单位px)
  28. * @event {Function} left 滑到左边事件
  29. * @event {Function} right 滑动右边事件
  30. */
  31. export default {
  32. name: 'fs-scroll-list'
  33. }
  34. </script>
  35. <script setup>
  36. import { onMounted, reactive, ref, computed, getCurrentInstance } from 'vue'
  37. const props = defineProps({
  38. indicator: {
  39. type: Boolean,
  40. default: true
  41. },
  42. indicatorWidth: {
  43. type: String,
  44. default: '30px'
  45. },
  46. indicatorBarWidth: {
  47. type: String,
  48. default: '15px'
  49. },
  50. indicatorColor: {
  51. type: String,
  52. default: '#f2f2f2'
  53. },
  54. indicatorActiveColor: {
  55. type: String,
  56. default: '#3c9cff'
  57. }
  58. })
  59. const emits = defineEmits(['left', 'right'])
  60. const state = reactive({
  61. listWidth: 0,
  62. contentWidth: 0,
  63. scrollWidth: 0
  64. })
  65. onMounted(() => {
  66. uni
  67. .createSelectorQuery()
  68. .in(getCurrentInstance().ctx)
  69. .select('.fs-scroll-list')
  70. .boundingClientRect(data => {
  71. state.listWidth = data.width
  72. })
  73. .exec()
  74. })
  75. const indicatorLeftWidth = computed(() => {
  76. return parseInt(props.indicatorWidth) - parseInt(props.indicatorBarWidth)
  77. })
  78. const listLeftWidth = computed(() => {
  79. return state.contentWidth - state.listWidth
  80. })
  81. const barStyle = computed(() => {
  82. const x = (state.scrollWidth * indicatorLeftWidth.value) / listLeftWidth.value + 'px'
  83. return `transform: translateX(${x})`
  84. })
  85. const handleScroll = event => {
  86. state.scrollWidth = event.detail.scrollLeft
  87. state.contentWidth = event.detail.scrollWidth
  88. }
  89. const handleToUpper = () => emits('left')
  90. const handleToLower = () => emits('right')
  91. </script>
  92. <style lang="scss" scoped>
  93. .fs-scroll-list {
  94. &-box {
  95. display: flex;
  96. }
  97. &-content {
  98. display: flex;
  99. flex-wrap: nowrap;
  100. }
  101. }
  102. .fs-scroll-indicator {
  103. display: flex;
  104. justify-content: center;
  105. &-line {
  106. background-color: v-bind(indicatorColor);
  107. width: v-bind(indicatorWidth);
  108. height: 8rpx;
  109. border-radius: 50px;
  110. overflow: hidden;
  111. }
  112. &-bar {
  113. background-color: v-bind(indicatorActiveColor);
  114. height: 8rpx;
  115. width: v-bind(indicatorBarWidth);
  116. border-radius: 50px;
  117. }
  118. }
  119. </style>