likes
comments
collection
share

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

作者站长头像
站长
· 阅读数 22

前言


《爱在黎明破晓前》 我见了你一面,便用一生去怀念

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

三部曲讲解了青春、中年、老年的爱情,触动挺多的。

一、前言

今天像往常一样,开开心心的打代码编程。

突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。

于是便有了今天这篇文章,一起来探讨一下。

当然,你也可以当做面试题。

二、分析

在我们的移动端,表单通过配置渲染表单类型。

而说回这次的下拉选择,一般选项不会超过100条,毕竟多了的话,也不好选择。

当然选项多了可以考虑,支持搜索功能。

那或许这又是另外一个问题。

  • 搜索调接口,在配置页添加接口url、入参query,即可远程搜索;

  • 又或者在这几万条数据中搜索过滤,都是可以配置选择。

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

如今我们需要解决如何在页面中显示这几万条数据选项。

很多人也习以为常搬出了虚拟列表。

在这之前,我们先来了解一下虚拟列表。

三、虚拟列表

虚拟列表是一种优化技术,仅对可见区域进行渲染,而非可见区域的数据则不渲染或部分渲染,从而减少资源消耗,提升用户体验。这种方法特别适合长列表,性能表现优异。

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

实现思路:

  1. 创建一个固定高度的 div,设置 overflow 以支持纵向滚动。
  2. 计算可视区域内可以显示的数据条数,即可视区域高度除以单条数据高度。
  3. 监听滚动事件,计算被卷起的数据的高度。
  4. 确定区域内数据的起始索引,通过卷起高度除以单条数据高度获得。
  5. 计算结束索引,即起始索引加上可显示的数据条数。
  6. 提取起始和结束索引之间的数据,渲染到可视区域。
  7. 设置起始索引在整个列表中的偏移位置,以更新列表内容。

不论如何滚动,只有滚动条的高度和可视区的元素内容会变化,始终保持渲染固定数量的元素,从而避免不必要的渲染开销。

对于刚接触的校友来说,可能有点小懵逼。

没关系,我们来看图。

dom元素

这是最外层的元素,设置死高度。

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

接着有一个元素是全部列表的数量*每一个项的高度(也就是完完整整数据的高度)

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

用父re子ab定位的形式,在计算top滚动了多少来定位

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

我计算这个高度(假如500px),每一个项50px,那一屏就加载10项

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

我一滚动,需要计算top和item(10项)

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

四、VirtualList

我们通过以上的图,大概明白了虚拟列表的实现,现在看看代码是如何实现的。

封装VirtualList组件

暴露了插槽slot,和listAll、itemHeight、contentHeight

<!--
 * @Description: 虚拟列表
-->
<template>
  <div :style="{ height: `${contentHeight}px` }" class="contentBox" @scroll="scroll">
  
    <div :style="{ height: `${itemHeight * listAll.length}px`, position: 'relative' }">
     
      <div :style="{ position: 'absolute', top: `${top}px`, width: '100%' }">
      
        <div v-for="(item, index) in showList" :key="index" class="item">
          <slot :item="item"></slot>
        </div>
      </div>
    </div>
  </div>
</template>
 
<script>
export default {
  name: "list",
  props: {
    // 所有数据
    listAll: {
      type: Array,
      default: () => [],
    },
    // 每条数据所占高度
    itemHeight: {
      type: Number,
      default: 50,
    },
    //可视区域高度
    contentHeight: {
      type: Number,
      default: 500,
    },
  },
  data() {
    return {
      showList: [], //可视区域显示的数据
      showNum: 0, //可是区域显示的最大条数
      top: 0, //偏移量
      scrollTop: 0, //卷起的高度
      startIndex: 0, //可视区域第一条数据的索引
      endIndex: 0, //可视区域最后一条数据后面那条数据的的索引
    };
  },
  methods: {
    getShowList() {
      this.showNum = Math.ceil(this.contentHeight / this.itemHeight); //可视区域最多出现的数据条数
      this.startIndex = Math.floor(this.scrollTop / this.itemHeight); 
      this.endIndex = this.startIndex + this.showNum; 
      this.showList = this.listAll.slice(this.startIndex, this.endIndex); 
      const offsetY = this.scrollTop - (this.scrollTop % this.itemHeight); 
      this.top = offsetY;
    },
    scroll() {
      this.scrollTop = document.querySelector(".contentBox").scrollTop; 
      this.getShowList();
    },
  },
  mounted() {
    this.scroll();
  },
};
</script>
 
<style scoped>
.contentBox {
  overflow: auto; /*内容超出高度才会出现滚动条*/
}
</style>

好的,我们看看父组件使用。

<van-radio-group v-model="result">
      <van-cell-group>
        <VirtualList :listAll="list" :itemHeight="52" :contentHeight="500">
          <template #default="{ item }">
            <van-cell :key="item.label" :title="item.label" clickable>
              <template #right-icon>
                <van-radio :name="item.value" />
              </template>
            </van-cell>
          </template>
        </VirtualList>

        <!-- <van-cell
          v-for="(item, index) in list"
          :key="index"
          :title="item.label"
          clickable
        >
          <template #right-icon>
            <van-radio :name="item.value" />
          </template>
        </van-cell> -->
      </van-cell-group>
    </van-radio-group>

这是可以直接使用到项目中的,放心使用。

虚拟列表,实战复制到项目中,解决几万条数据滚动卡顿突然产品说下载下拉选择有将近20000项,移动端点击选项比较卡。 而说

这样子实现后:

  1. 性能提升:只渲染可见区域,显著减少DOM操作,提升渲染速度。
  2. 内存节省:避免一次性加载所有数据,降低内存消耗。
  3. 流畅体验:用户滚动时响应迅速,提供平滑的浏览体验。
  4. 易于扩展:适用于大数据集,方便进行数据分页或无限滚动加载。

至此撒花~

后记

我们在实际项目中或多或少遇到一些奇奇怪怪的问题。

自己也会对一些写法的思考,为什么不行🤔,又为什么行了?

最后,祝君能拿下满意的offer。

👍 如果对您有帮助,您的点赞是我前进的润滑剂。

以往推荐

原文链接

转载自:https://juejin.cn/post/7418460243501629467
评论
请登录