uniapp vue3 虚拟下拉滚动 初始版

下面是vue3的写法   如果想查看vue2的写法   请移步至github链接    https://github.com/Arvin-Cui/vue-virtual-scroll/blob/master/pages/index/index.vue
1.
index.vue    index.vue页面中加一个共用组件VirtualList.vue
<template>
  <view>
    <VirtualList :listData="state.dateList" :itemSize="100"></VirtualList>
  </view>
</template>
  <script setup lang="ts">
import { reactive } from 'vue'
import { onShow } from '@dcloudio/uni-app'
const state = reactive({
  dateList: []
})
onShow(() => {
  inits()
})
const inits = () => {
  state.dateList = [
    { name: 1 },{ name: 2 }, { name: 3 }, { name: 4 },{ name: 5 }, { name: 6 }, { name: 7 },{ name: 8 },{ name: 9 }, { name: 10 },
    { name: 11 },{ name: 12 },{ name: 13 },{ name: 14 },{ name: 15 },{ name: 16 },{ name: 17 },{ name: 18 },{ name: 19 },{ name: 20 },
    { name: 21 },{ name: 22 },{ name: 23 },{ name: 24 },{ name: 25 },{ name: 26 },{ name: 27 },{ name: 28 },{ name: 29 },{ name: 30 },
    { name: 31 },{ name: 32 },{ name: 33 },{ name: 34 },{ name: 35 },{ name: 36 },{ name: 37 },{ name: 38 },{ name: 39 },{ name: 40 },
    { name: 41 },{ name: 42 },{ name: 43 },{ name: 44 },{ name: 45 },{ name: 46 },{ name: 47 },{ name: 48 },{ name: 49 },{ name: 50 },
    { name: 51 },{ name: 52 },{ name: 53 },{ name: 54 },{ name: 55 },{ name: 56 },{ name: 57 },{ name: 58 },{ name: 59 },{ name: 60 },
    { name: 61 },{ name: 62 },{ name: 63 },{ name: 64 },{ name: 65 },{ name: 66 },{ name: 67 },{ name: 68 },{ name: 69 },{ name: 70 },
    { name: 71 },{ name: 72 },{ name: 73 },{ name: 74 },{ name: 75 },{ name: 76 },{ name: 77 },{ name: 78 },{ name: 79 },{ name: 80 },
    { name: 81 },{ name: 82 },{ name: 83 },{ name: 84 },{ name: 85 },{ name: 86 },{ name: 87 },{ name: 88 },{ name: 89 },{ name: 90 },
 { name: 91 },{ name: 92 },{ name: 93 },{ name: 94 },{ name: 95 },{ name: 96 },{ name: 97 },{ name: 98 }, { name: 99 },{ name: 100 },
 { name: 101 },{ name: 102 }, { name: 103 }, { name: 104 },{ name: 105 }, { name: 106 }, { name: 107 },{ name: 108 },{ name: 109 }, { name: 110 },
    { name: 111 },{ name: 112 },{ name: 113 },{ name: 114 },{ name: 115 },{ name: 116 },{ name: 117 },{ name: 118 },{ name: 119 },{ name: 120 },
    { name: 121 },{ name: 122 },{ name: 123 },{ name: 124 },{ name: 125 },{ name: 126 },{ name: 127 },{ name: 128 },{ name: 129 },{ name: 130 },
    { name: 131 },{ name: 132 },{ name: 133 },{ name: 134 },{ name: 135 },{ name: 136 },{ name: 137 },{ name: 138 },{ name: 139 },{ name: 140 },
    { name: 141 },{ name: 142 },{ name: 143 },{ name: 144 },{ name: 145 },{ name: 146 },{ name: 147 },{ name: 148 },{ name: 149 },{ name: 150 },
    { name: 151 },{ name: 152 },{ name: 153 },{ name: 154 },{ name: 155 },{ name: 156 },{ name: 157 },{ name: 158 },{ name: 159 },{ name: 160 },
    { name: 161 },{ name: 162 },{ name: 163 },{ name: 164 },{ name: 165 },{ name: 166 },{ name: 167 },{ name: 168 },{ name: 169 },{ name: 170 },
    { name: 171 },{ name: 172 },{ name: 173 },{ name: 174 },{ name: 175 },{ name: 176 },{ name: 177 },{ name: 178 },{ name: 179 },{ name: 180 },
    { name: 181 },{ name: 182 },{ name: 183 },{ name: 184 },{ name: 185 },{ name: 186 },{ name: 187 },{ name: 188 },{ name: 189 },{ name: 190 },
 { name: 191 },{ name: 192 },{ name: 193 },{ name: 194 },{ name: 195 },{ name: 196 },{ name: 197 },{ name: 198 }, { name: 199 },{ name: 200 },
  ]
}
</script>
<style lang="scss" scoped>
</style>
 
2.VirtualList.vue 页面  逻辑都在这个页面
    <
template>
  <view class="content">
    <!-- 使用 scroll-view 组件来实现滚动 -->
    <scroll-view
      ref="list"
      scroll-y="true"
      class="list-container"
      @scroll="handleScroll"
      style="height: 100vh"
      :scroll-top="state.startOffset"
    >
      <view class="list-phantom" :style="{ height: listHeight + 'px' }"></view>
      <view class="list" :style="{ transform: getTransform }">
        <view
          v-for="(item, index) in visibleData"
          class="list-item"
          :key="index"
          :style="{ height: props.itemSize + 'px', lineHeight: props.itemSize + 'px' }"
        >
          {{ item.name }}
        </view>
      </view>
    </scroll-view>
  </view>
</template>
<script setup lang="ts">
import { reactive, onMounted, computed } from 'vue'
import { debounce } from '@/utils/tools'
const state = reactive({
  listHeight: 0,
  screenHeight: 0, // 屏幕高度即可视区域高度
  startOffset: 0, // 顶部偏移量
  startIndex: 0, // 可视化区域的数据开始下标
  endIndex: 0 // 可视化区域的数据结束下标
})
const props = defineProps({
  listData: {
    type: Array,
    default: () => []
  },
  //每项高度
  itemSize: {
    type: Number,
    default: 200
  }
})
const listHeight = computed(() => {
  return props.listData.length * props.itemSize
})
const visibleCount = computed(() => {
  return Math.ceil(state.screenHeight / props.itemSize) || 0
})
const getTransform = computed(() => {
  return 'translate3d(0,' + state.startOffset + 'px,0)'
})
const visibleData = computed(() => {
  return props.listData.slice(state.startIndex, Math.min(state.endIndex, props.listData.length))
})
onMounted(() => {
  console.log(props.listData)
  init()
})
const init = () => {
  getScreenHeight()
  // 设置初始滚动距离  state.startIndex = 0   如果不是从第一个开始滚动 num为第几个开始  state.startIndex = num  state.startOffset = num * props.itemSize
  //   state.startIndex = 0
  state.startIndex = 20
  state.startOffset = 20 * props.itemSize
  state.endIndex = state.startIndex + visibleCount.value
}
 
// 获取屏幕高度即可视化区域高度
const getScreenHeight = () => {
  uni.getSystemInfo({
    success: function (res) {
      state.screenHeight = res.screenHeight
    }
  })
}
// 防抖 节流方法   debounce第三个参数没用  可以删除
const debounce= (fn, delay,_this) => {
  vardelay = delay || 200
var timer = null
return function () {
let self = _this || this
let args = arguments
timer && clearTimeout(timer)
timer = setTimeout(function () {
timer = null
fn.apply(self, args)
    }, delay)
  }
}
const handleScroll = debounce(
  (e) => {
    //当前滚动位置
    let scrollTop = e.detail.scrollTop
    //开始索引
    state.startIndex = Math.floor(scrollTop / props.itemSize)
    //结束索引
    state.endIndex = state.startIndex + visibleCount.value
    //顶部偏移量
    state.startOffset = scrollTop - (scrollTop % props.itemSize)
  },
  10,
  ''
)
</script>
<style lang="scss" scoped>
.list-container {
  height: 100%;
  overflow: auto;
  position: relative;
  .list-phantom {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    z-index: -1;
  }
  .list {
    left: 0;
    right: 0;
    top: 0;
    position: absolute;
    .list-item {
      text-align: center;
      border-bottom: 1px solid #ccc;
    }
  }
}
</style>
 
 最终效果图

posted @ 2024-06-20 14:12  风雪中de冲破  阅读(66)  评论(0编辑  收藏  举报