【vue3】前端虚拟列表实现

183 阅读3分钟

虚拟列表是什么?

虚拟列表是一种长列表优化方案,因为当数据堆积过多,页面列表需要渲染大量dom时,会造成性能的巨大消耗,而虚拟列表仅渲染可视区域的数据,节省了网页的性能开销,避免数据过多时引起的网页卡顿。

目前,虚拟列表的实现主要分为两种:

  1. 列表项高度固定的虚拟列表实现,列表中的每一项的高度都固定不变。
  2. 列表项高度不定的虚拟列表实现,因为文本内容的不一致,导致每一项列表的高度可能不同,相较于上一种,实现更为复杂,本文暂不涉及。

本文主要内容为高度固定的虚拟列表实现

虚拟列表实现

  1. 虚拟列表的实现总归需要以下几点关键属性:
  • itemSize:每一项列表项的高度.
  • itemCount:可视区域的需要渲染的列表项数量.
  • startItem:渲染数组的起始索引.
  • areaHeight:可视区域的高度,areaHeight= itemCount * itemSize.
  • endItem:渲染数组的结束索引.
  • topOffset:渲染列表的起始项距离顶部的偏移量.
  • listLength:数据列表的长度.
  • listHeight:列表的总高度(滚动区域的总高度),listHeight=listLength * itemSize
  • sliceData:从数据列表中根据startItem和endItem截取出的数据,用作渲染dom.
  1. 虚拟列表的实现原理:

image.png

  • 基本原理:由可视区域包含着滚动区域,滚动区域包括占位元素和需要渲染的列表table(占位元素用于提供滚动效果),通过可视区域绑定滚动事件,计算出当前可视区域中需要渲染的数据索引以及偏移量,从数据列表中截取到对应的数据sliceData,再渲染和展示出对应的dom节点和区域。
<div @scroll="handleScroll" :style="{ height: areaHeight +'px'}">
         <div :style="{ height: listHeight + 'px' }"></div> //占位元素
            <div :style="{ transform: `translateY(${topOffset}px)` }"> //需要渲染的列表
              <div v-for="item in sliceData" :key="item.id">
              </div>
            </div>
</div>

image.png

  • 详细实现:当滑动时,根据scrollTop / itemSize 计算出移动了几项,得到新的startItem,并根据startItem+ itemCount 得到endItem,可得sliceData,再根据startItem * itemSize得到偏移的数值topOffset,保持渲染列表始终处于可视区域(因为渲染列表是处于滚动区域顶部的,滚动区域滑上去后,渲染列表的dom区域也会随之向上滑,所以需要添加偏移值让它保持在可视区域内)
      const handleScroll = (e) => {
        startItem.value = Math.floor(e.target.scrollTop / itemSize);
      };
      let endItem = computed(() => {
        return startItem.value + itemCount;
      });
      let topOffset = computed(() => {
        return startItem.value * itemSize;
      });

至此,完成了高度固定的虚拟列表的实现。

踩坑

注意渲染列表的区域和滚动区域一定不能是同一个dom元素,否则因为添加了偏移值,会导致滚动区域可以无限滑动,哪怕数据没有了也可以继续向下滑,所以一定要将一个单独的占位元素作为滚动区域,渲染列表的区域和滚动区域分离开。