虚拟列表——一次性请求大量数据优化
情景:
后端一次性传了10000条数据(假设存在),需要前端展示。若真的一次性全部展示出来性能消耗大,一万条数据不明显,十万条呢,肯定会导致页面卡顿的。
实现思路:
使用虚拟列表实现,其实和分页类似,就是前端自己裁剪数据,一次性值展现固定量的数据。如果使用element-plus可以直接使用他们的虚拟化表格,这里就不过多展示了。
布局:三个div,大的容器,大的放滚动事件,里面放两个小的div,一个用来撑开容器,另一个作为可视区域。
步骤1:监听滚动事件,在里面获取scrollTop,计算开始位置,开始位置其实就是scrollTop/height。
步骤2:按长度切割数组,获取需要渲染的内容。
<script setup lang="ts"> import { computed, onMounted, reactive, ref } from "vue"; let start = ref(0), size = ref(10), height = ref(20), scrollTop = ref(0), totalList = reactive<string[]>([]); const virtualListRef = ref(null); onMounted(() => { for (let i = 0; i < 10000; i++) { totalList.push(`第${i}个`); } virtualListRef.value.style.height = height.value * size.value + "px"; }); // 需要渲染的数组 const renderList = computed(() => { return totalList.slice(start.value, start.value + size.value); }); const handleScroll = () => { scrollTop.value = virtualListRef.value.scrollTop; // 开始的位置等于滚动的距离除高度 start.value = scrollTop.value / height.value; }; </script>
HTML
<template> <div class="wrapper"> <div id="virtualList" ref="virtualListRef" @scroll="handleScroll"> <!-- 空白div --> <div :style="{ height: totalList.length * height + 'px' }"></div> <!-- 可视区域 --> <div class="container" :style="{ top: scrollTop + 'px' }"> <div class="item" v-for="item in renderList" :style="{ height: height + 'px' }" > {{ item }} </div> </div> </div> </div> </template>
CSS
<style scoped> #virtualList { position: relative; overflow: auto; width: 200px; height:200px; border: 1px green solid; } .container { position: absolute; left: 0; top: 0; width: 100%; } </style>
效果图