fs-scroll-list.vue 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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">
  13. <slot></slot>
  14. </view>
  15. </scroll-view>
  16. <view class="fs-scroll-indicator" v-if="indicator">
  17. <view class="fs-scroll-indicator-line">
  18. <view class="fs-scroll-indicator-bar" :style="barStyle"></view>
  19. </view>
  20. </view>
  21. </view>
  22. </template>
  23. <script>
  24. export default {
  25. name: 'fs-scroll-list'
  26. }
  27. </script>
  28. <script setup>
  29. import { onMounted, reactive, ref, computed, getCurrentInstance } from 'vue'
  30. const props = defineProps({
  31. indicator: {
  32. type: Boolean,
  33. default: true
  34. },
  35. indicatorWidth: {
  36. type: String,
  37. default: '30px'
  38. },
  39. indicatorBarWidth: {
  40. type: String,
  41. default: '15px'
  42. },
  43. indicatorColor: {
  44. type: String,
  45. default: '#f2f2f2'
  46. },
  47. indicatorActiveColor: {
  48. type: String,
  49. default: '#3c9cff'
  50. }
  51. })
  52. const emits = defineEmits(['left', 'right'])
  53. const state = reactive({
  54. listWidth: 0,
  55. contentWidth: 0,
  56. scrollWidth: 0
  57. })
  58. onMounted(() => {
  59. uni.createSelectorQuery().in(getCurrentInstance().ctx).select('.fs-scroll-list').boundingClientRect(data => {
  60. state.listWidth = data.width
  61. }).exec()
  62. })
  63. const indicatorLeftWidth = computed(() => {
  64. return parseInt(props.indicatorWidth) - parseInt(props.indicatorBarWidth)
  65. })
  66. const listLeftWidth = computed(() => {
  67. return state.contentWidth - state.listWidth
  68. })
  69. const barStyle = computed(() => {
  70. const x = state.scrollWidth * indicatorLeftWidth.value / listLeftWidth.value + 'px'
  71. return `transform: translateX(${x})`
  72. })
  73. const handleScroll = event => {
  74. state.scrollWidth = event.detail.scrollLeft
  75. state.contentWidth = event.detail.scrollWidth
  76. }
  77. const handleToUpper = () => emits('left')
  78. const handleToLower = () => emits('right')
  79. </script>
  80. <style lang="scss" scoped>
  81. .fs-scroll-list{
  82. &-box{
  83. display: flex;
  84. }
  85. &-content{
  86. display: flex;
  87. flex-wrap: nowrap;
  88. }
  89. }
  90. .fs-scroll-indicator{
  91. display: flex;
  92. justify-content: center;
  93. &-line{
  94. background-color: v-bind(indicatorColor);
  95. width: v-bind(indicatorWidth);
  96. height: 8rpx;
  97. border-radius: 50rpx;
  98. overflow: hidden;
  99. }
  100. &-bar{
  101. background-color: v-bind(indicatorActiveColor);
  102. height: 8rpx;
  103. width: v-bind(indicatorBarWidth);
  104. border-radius: 50px;
  105. }
  106. }
  107. </style>