美文网首页
虚拟滚动实现

虚拟滚动实现

作者: 芸芸众生ing | 来源:发表于2022-11-14 11:57 被阅读0次
<!--
Name: 虚拟滚动实现
Date  : 2022-11-15
-->
<template>
  <div class="box" ref="boxRef" @scroll="scroll">
    <div class="scroll-box" :style="{ height: scrollHeight }">
      <div ref="itemRef" style="overflow:hidden;position: absolute;top:0;left:0;right:0" v-for="item, i in currArr"
        :key="item" :style="{ transform: `translateY(${App.getPxtoRem((startIdx + i) * itemHeight)}rem)` }">
        <div class="item">{{ item }}</div>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts" name="test">
import { nextTick, ref } from 'vue';
import { useAppStore } from './pinia/app';
const length = 5;
const App = useAppStore();
const arr = new Array(17).fill(1).map((e, i) => i + 1);

// 
const boxRef = ref<HTMLDivElement>();
const itemRef = ref<HTMLDivElement[]>();
const itemHeight = ref(0);
// 默认滚动盒子高度与父盒子一样
const scrollHeight = ref('100%');
// 开始下标
const startIdx = ref(0);
// 结束下标
const endIdx = ref(length);
// 渲染的数据
const currArr = ref<any[]>();
// 当前滚动位置
const scrollTop = ref(0);
// 初始渲染
renderDom();
nextTick(() => {
  // 获取单个内容高度
  itemHeight.value = (itemRef.value && itemRef.value[0] as HTMLDivElement)?.clientHeight || 0;
  // 获取内容总高度
  scrollHeight.value = useAppStore().getPxtoRem(arr.length * itemHeight.value) + 'rem';
})

function scroll() {
  // 获取滚动距离
  scrollTop.value = boxRef.value?.scrollTop || 0;
  // 计算当前偏移下标
  let start = Math.floor(scrollTop.value / itemHeight.value) - 1;
  // 如果不等于上一次滚动的偏移下标
  if (startIdx.value != start) {
    // 计算结束下标
    let end = start + length;
    // 如果开始下标小于0,就重置为0;
    if (start < 0) start = 0;
    // 如果结束下标大于内容末尾,重置为末尾一个
    if (end > arr.length) end = arr.length;
    startIdx.value = start;
    endIdx.value = end;
    renderDom();
  }
}

function renderDom() {
  // 截取渲染的数据内容
  currArr.value = arr.slice(startIdx.value, endIdx.value)
}
</script>
<style lang="scss" scoped>
.box {
  max-height: 600px;
  overflow: hidden;
  overflow-y: auto;
  width: 375px;
  margin: auto;

  .scroll-box {
    position: relative;

    .item {
      height: 200px;
      margin-bottom: 10px;
      background: #ccc;
    }
  }
}
</style>

相关文章

网友评论

      本文标题:虚拟滚动实现

      本文链接:https://www.haomeiwen.com/subject/esddxdtx.html