vue3 简单实现虚拟列表

488 阅读1分钟

前段时间看了下element-plus的 Select V2 虚拟列表选择器,感觉还挺有意思的,按照自己的思路简单模拟了一下

首先我们了解下为什么要使用虚拟列表?

虚拟列表主要是解决当列表数量较多时(比如上十万条数据、百万万条数据),页面内引入大量的 DOM 元素导致页面卡顿的情况,当然对于列表数量没达到足够的量级(主要根据自己的业务来衡量)但是想提高首屏加载速度时,也可以选择按需加载列表,类似于图片的懒加载,并非一次性渲染全部列表,而在滚动到页面底部的时候,再去加载剩余的数据。但是对于业务需求就是一次性返回所有数据的时候选择用虚拟列表去加载更合适。

先看下没做处理渲染十万条数据的dom加载情况:

图里我们可以看到dom 的渲染加载时间需要三四十秒,要是数据量达到百万的话看到页面估计得等到下班了~~

那么接下来我开始介绍虚拟列表的实现:

思路就是用vue的for循环渲染列表,自己手动加一个滚动条,然后通过监听scroll,算出应该显示到第几个,加载对应区域的数据,列表项的dom数量始终不变。

来吧,我们直接上代码:

script部分:

<script lang="ts">
import { ref } from 'vue'
export default {
  setup() {
    let min = ref(2)
    const getScroll = (event: any) => {
      let scrollTop = event.target.scrollTop
      // 当滚动距离大于2条数据的高度时开始动态计算
      if (scrollTop > 2 * 40) {
        min.value = Math.ceil(scrollTop / 40)
      } else {
        min.value = 2
      }
    }

    return {
      // 构造十万条数据
      options: ref(
        Array.from({ length: 1000000 }).map((_, idx) => ({
          value: `Option ${idx + 1}`,
          label: `${idx}`,
        }))
      ),
      getScroll,
      min,
    }
  },
}
</script>

html部分:

<template>
  <h3>vitlist</h3>
  <div class="list" ref="listRef" @scroll.passive="getScroll($event)">
    <!-- 为了方便我把每一项的高度写死40,展示的条数十条 -->
    <div :style="{ height: 40 * options.length + 'px', width: '100%' }">
      <div
        class="item"
        v-for="(item, index) in options.slice(min - 2, min + 10)"
        :key="index"
        :style="{ top: `${40 * item.label}px` }"
      >
        {{ item.value }}:{{ item.label }}
      </div>
    </div>
  </div>
</template>

style部分:

<style lang="less" scoped>
.list {
  margin: 10px auto;
  width: 300px;
  height: 200px;
  overflow: auto;
  position: relative;
  .item {
    height: 40px;
    line-height: 40px;
    position: absolute;
    width: 100%;
  }
}
</style>

看下效果:(百万条数据页面渲染也就1-2秒)

好了以上分享到这里。

分享不易,你们的点赞是对我最大的鼓励,欢迎评论交流哈