快速掌握【虚拟列表】

618 阅读4分钟

【前言】

在 Web 开发中,列表页的性能优化一直是开发者们非常关注的话题。当列表数据量比较大的时候,渲染整个列表会导致页面卡顿、内存占用过高,影响用户体验。因此,虚拟列表(Virtual List)应运而生,它只渲染可视区域内的列表数据,从而提高了列表页的性能和用户体验。

这篇文章主要是为了让各位uu能够快速掌握【虚拟列表】技术,所以没有介绍的很深入,想要完完整整了解这一技术可以去看看「前端进阶」高性能渲染十万条数据(虚拟列表)这篇文章,写的真的很详细。

【什么是虚拟列表】

虚拟列表(Virtual List)是指只渲染可视区域内的列表数据,而不是渲染所有列表数据的一种优化技术。 它可以有效地减少页面的渲染时间和内存占用,提高页面的加载和渲染性能,特别是当列表数据量很大的时候,应用虚拟列表可以显著提升用户体验。

【虚拟列表的实现原理】

实现虚拟列表的原理与技术主要有两种:一种是基于绝对定位实现的,另一种是基于滚动监听实现的。

第一种基于绝对定位的实现方法,是通过计算可视区域的高度和每个列表项的高度,然后根据列表项的索引值计算出每个列表项应该在哪个位置上进行绝对定位,并通过 CSS 样式进行定位。在滚动时,只需要根据滚动距离重新计算需要定位的列表项即可。

第二种基于滚动监听的实现方法,是通过监听滚动事件,计算出可视区域的开始和结束索引,然后只渲染这些需要显示的列表项。在滚动时,只需要重新计算可视区域的开始和结束索引,然后更新需要显示的列表项即可。

虚拟列表的实现可以有效地减少页面的渲染时间和内存占用,提高页面的加载和渲染性能,特别是当列表数据量很大的时候,应用虚拟列表可以显著提升用户体验。

【如何实现虚拟列表】

简单粗暴,实现虚拟列表可以使用第三方库,如 React-Virtualized、vue-virtual-scroller 等。这些库已经封装了虚拟列表的实现原理,可以方便地在项目中使用。这里简单介绍几个支持vue3的三方库:

  • vue-virtual-scroller: 这是一个基于 Vue 3 的虚拟滚动列表组件,可以用于大型数据集的渲染。它支持水平和垂直方向的滚动,并且具有无限滚动、缓存、动态高度等功能。
  • vue3-virtual-scroll-list: 这是一个支持垂直方向的无限滚动列表组件,可以用于渲染大量数据。它支持异步加载、滚动到指定位置、动态高度等功能。
  • vue3-infinite-scroll: 这是一个支持无限滚动的 Vue 3 组件,可以用于渲染大量数据。它支持异步加载、滚动到指定位置、动态高度等功能。
  • vue-lazy-render: 这是一个基于 Vue 3 的懒加载组件,可以用于渲染大量数据。它支持滚动监听、动态高度、动画效果等功能。

当然,如果想自己实现虚拟列表,可以按照以下步骤:

步骤一:计算列表项的高度和可视区域的高度,从而可以得到可视区域内最多可以显示多少个列表项。

步骤二:在渲染列表的时候,只渲染可视区域内的列表项,并在列表项上应用绝对定位或者滚动监听。

步骤三:在滚动时,重新计算需要渲染的列表项,更新可视区域内的列表项。

话不多说,直接上代码:(这是一个实现虚拟列表基本功能的代码,适用于掌握虚拟列表。)

<template>
  <div ref="container" class="container" @scroll="handleScroll">
    <div class="list-wrapper" :style="{ height: listHeight + 'px' }">
      <div
        v-for="item in visibleItems"
        :key="item.id"
        class="list-item"
        :style="{ top: item.top + 'px', height: itemHeight + 'px' }"
      >
        {{ item.name }}
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from "vue";

interface ListItem {
  id: number;
  name: string;
  top: number;
}

// 容器的ref
const container = ref();
// 所有列表数据
const items = ref<ListItem[]>([]);
// 需要渲染的数据
const visibleItems = ref<ListItem[]>([]);
// 子组件的高度
const itemHeight = 50;
// 容器滚动高度
let scrollTop = 0;

// 占位区域高度,也就是整个列表的高度,用于生成滚动条
const listHeight = computed(() => items.value.length * itemHeight);

onMounted(() => {
  // 循环造数据
  for (let i = 0; i < 10000; i++) {
    items.value.push({ id: i, name: `Item ${i}`, top: i * itemHeight });
  }

  updateVisibleItems();
});

// 更新需要渲染的数据
function updateVisibleItems() {
  const startIndex = Math.floor(scrollTop / itemHeight);
  const endIndex = Math.min(
    startIndex + Math.ceil(container.value.clientHeight / itemHeight) + 1,
    items.value.length
  );
  visibleItems.value = items.value.slice(startIndex, endIndex).map((item, index) => ({
    ...item,
    top: (startIndex + index) * itemHeight,
  }));
}

// 监听滚动事件
function handleScroll(event: Event) {
  const target = event.target as HTMLElement;
  scrollTop = target.scrollTop;
  updateVisibleItems();
}
</script>

<style scoped lang="scss">
.container {
  height: 500px;
  overflow-y: scroll;

  .list-wrapper {
    position: relative;

    .list-item {
      position: absolute;
      left: 0;
      right: 0;
      text-align: center;
    }
  }
}
</style>

【虚拟列表的优缺点】

虚拟列表的优点在于可以提高页面的性能和用户体验,特别是当列表数据量很大的时候。虚拟列表只渲染可视区域内的列表数据,减少了页面的渲染时间和内存占用,从而提高了页面的加载和渲染性能。

虚拟列表的缺点在于实现相对比较复杂,需要对列表高度、滚动事件等进行精确计算。另外,在某些情况下,虚拟列表会导致列表项的高度不一致,影响页面的美观度。

【总结】

虚拟列表是一种非常实用的性能优化技术,在处理大量列表数据时可以提高页面的性能和用户体验。实现虚拟列表可以使用第三方库或者自己实现,但需要注意计算列表高度、滚动事件等细节问题。