• 作者:老汪软件技巧
  • 发表时间:2024-09-27 15:01
  • 浏览量:

前言

《爱在黎明破晓前》

我见了你一面,便用一生去怀念

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

一、前言

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

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

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

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

二、分析

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

如果有兴趣的话,可以移步:Vue如何高效通过JSX动态渲染组件

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

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

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

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

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

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

三、虚拟列表

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

实现思路:

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

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

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

没关系,我们来看图。

dom元素

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

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

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

_vxe-table虚拟滚动_js虚拟滚动列表

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

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

四、VirtualList

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

封装VirtualList组件

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


<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>

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

"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-group>
    

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

这样子实现后:

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

至此撒花~

后记

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

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

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

我是Dignity_呱,来交个朋友呀,有朋自远方来,不亦乐乎呀!深夜末班车

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

以往推荐

小小导出,我大前端足矣!

靓仔,说一下keep-alive缓存组件后怎么更新及原理?

面试官问我watch和computed的区别以及选择?

面试官问我new Vue阶段做了什么?

前端仔,快把dist部署到Nginx上

多图详解,一次性啃懂原型链(上万字)

Vue-Cli3搭建组件库

Vue实现动态路由(和面试官吹项目亮点)

项目中你不知道的Axios骚操作(手写核心原理、兼容性)

VuePress搭建项目组件文档

原文链接

/spost/74184…