前端虚拟滚动列表 vue虚拟列表

news2025/1/10 2:29:31

前端虚拟滚动列表

在大型的企业级项目中经常要渲染大量的数据,这种长列表是一个很普遍的场景,当列表内容越来越多就会导致页面滑动卡顿、白屏、数据渲染较慢的问题;大数据量列表性能优化,减少真实dom的渲染


看图:绿色是显示区域,绿色和蓝色中间属于预加载:解决滚动闪屏问题;大致了解了流程在往下看;
在这里插入图片描述

实现效果:

先说一下你看到这么多真实dom节点是因为做了预加载,减少滚动闪屏现象,这里写了300行,可以根据实际情况进行截取
在这里插入图片描述

实现思路:

虚拟列表滚动大致思路:两个div容器

  外层:外部容器用来固定列表容器的高度,同时生成滚动条

  内层:内部容器用来装元素,高度是所有元素高度的和

  外层容器鼠标滚动事件  dom.scrollTop 获取滚动条的位置

  根据每行列表的高以及当前滚动条的位置,利用slice() 去截取当前需要显示的内容

  重点:滚动条的高度是有内层容器的paddingBottom 和 paddingTop 属性顶起来了,确保滚动条位置的准确性

  这里鼠标上下滚动会出现闪屏问题:解决方案如下:

      方案一:  预加载:

                    向下预加载:
                        比如div滚动区域显示30行,就预加载 300行( 即这里 slice(startIndex,startIndex + 300) ),

                    向上预加载:
                        在滚动监听事件函数中(computeRow)判断inner的paddingTop和paddingBottom即可

                    当然这里的download-box的padding有30px像素,在加一个div,overflow:hidded就解决了

      方案二:缩小滚动范围或者节流时间缩短,这里写的500ms

具体代码

  <template>
    <div class="enn">
      <div class="download-box txt" id="scrollable-div" @scroll="handleScroll">
        <div id="inner">
          <div v-for="(item, index) in data2" :key="index" class="line-box">
            <div :class="{ 'text-box': props.collapsed, 'text-box-samll': !props.collapsed }">
              {{ item }}
            </div>
          </div>
        </div>
      </div>
    </div>
  </template>

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

  import { useText } from './hooks/useText';

  const props = defineProps({
    baseData: {
      type: Object as PropType<{
        taskId: string;
        barcodeName: string;
      }>,
      default: {},
    },
    collapsed: {
      type: Boolean,
      default: true,
    },
    type: {
      type: Boolean,
      default: false,
    },
  });

  const { data } = useText(props.type);

  //  这里大数据量数组是  data.geneTexts

  /**
   * 虚拟列表滚动大致思路:两个div容器
   *
   *    外层:外部容器用来固定列表容器的高度,同时生成滚动条
   *
   *    内层:内部容器用来装元素,高度是所有元素高度的和
   *
   *    外层容器鼠标滚动事件  dom.scrollTop 获取滚动条的位置
   *
   *    根据每行列表的高以及当前滚动条的位置,利用slice() 去截取当前需要显示的内容
   *
   *    重点:滚动条的高度是有内层容器的paddingBottom 和 paddingTop 属性顶起来了,确保滚动条位置的准确性
   *
   *    这里鼠标上下滚动会出现闪屏问题:解决方案如下:
   *
   *        方案一:  预加载:
   *
   *                      向下预加载:
   *                          比如div滚动区域显示30行,就预加载 300行( 即这里 slice(startIndex,startIndex + 300) )*
   *                      向上预加载:
   *                          在滚动监听事件函数中(computeRow)判断inner的paddingTop和paddingBottom即可
   *
   *                      当然这里的download-box的padding有30px像素,在加一个div,overflow:hidded就解决了
   *
   *        方案二:缩小滚动范围或者节流时间缩短,这里写的500ms
   *
   *
   */

  let timer_throttle: any;
  const throttle = (func: Function, wait?: number) => {
    wait = wait || 500;
    if (!timer_throttle) {
      timer_throttle = setTimeout(() => {
        func.apply(this);
        timer_throttle = null;
      }, wait);
    }
  };

  // 鼠标滚动事件
  const handleScroll = (event: any) => throttle(computeRow, 100);
  // 计算当前显示tab
  const computeRow = () => {
    // console.log('距离顶部距离', window.scrollY, geneTexts);

    let scrollableDiv = document.getElementById('scrollable-div');
    let topPosition = scrollableDiv.scrollTop;
    let leftPosition = scrollableDiv.scrollLeft;
    console.log('垂直滚动位置:', topPosition, '水平滚动位置:', leftPosition);

    const startIndex = Math.max(0, Math.floor(topPosition / 30));
   
    const endIndex = startIndex + 300;
    data2.value = data.geneTexts.slice(startIndex, endIndex);

    let inner = document.getElementById('inner');
    if (topPosition < 2700) {
      // 向上预计加载,这里判断了三个高度,可以多判断几个,增加流畅度
      inner.style.paddingTop = topPosition + 'px';
      inner.style.paddingBottom = (data.geneTexts.length + 2) * 30 - topPosition + 'px';
    } else if (topPosition + data2.value.length * 30 >= data.geneTexts.length * 30) {
      // 这里 9000 是 内层div的高度 30 * 300   理解div高度是 padding+div内容高度
      inner.style.paddingTop = topPosition - 900 + 'px'; //900 是div的高度
      inner.style.paddingBottom = 0 + 'px';
    } else {
      inner.style.paddingTop = topPosition - 2700 + 'px';
      inner.style.paddingBottom = (data.geneTexts.length + 2) * 30 + 2700 - topPosition + 'px';
    }
  };
  const data2 = ref([]);
  const init = () => {
    data2.value = data.geneTexts.slice(0, 300);
    let inner = document.getElementById('inner');
    inner.style.paddingTop = 0 + 'px';
    inner.style.paddingBottom = (data.geneTexts.length + 2) * 30 - 900 + 'px';
  };
  </script>

  <style lang="less" scoped>
  .button-box {
    margin-bottom: 25px;
    .flex-type(flex-end);

    :deep(.ant-btn) {
      margin-left: 10px;
    }
  }
  .enn {
    background: #282c34;
    outline: 1px solid red;
    padding: 30px 20px;
    height: 960px;
  }
  .download-box {
    width: 100%;
    // padding: 30px 20px;
    outline: 1px solid rgb(17, 0, 255);
    background-color: #fff;
    overflow: hidden;

    .line-box {
      .flex-type(flex-start);
      height: 30px;
    }

    &.txt {
      background: #282c34;
      color: #fff;
      height: 900px;
      overflow: auto;
    }
  }
  </style>

替代方案

上面是自己写的,github上面还有好多插件可以用,但各有优劣,根据自己需求选择
如:

vue-virtual-scroller

https://github.com/Akryum/vue-virtual-scroller/tree/0f2e36248421ad69f41c9a08b8dcf7839527b8c2

vue-virt-list

vue-draggable-virtual-scroll-list

virtual-list

自己找吧,我就不一一列举了,看图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1559240.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

攻防世界——catfly

这道题我觉得很难&#xff0c;我当初刷题看见这道题&#xff0c;是唯一一道直接跳过的&#xff0c;现在掌握了一点知识才回来重新看 这道题在linux运行下是这样&#xff0c;我首先猜测是和下面这个time有关&#xff0c;判断达到一定次数就会给我flag 但是我找了好久都没找到那…

NFT-前端开发(一)

使用 在我们想要保存项目的目录下打开终端运行npx create-react-app test2命令初始化&#xff0c;test2是我们的项目名字&#xff0c;可以自己去更改。 初始化完成后&#xff0c;我们目录下就会多出一个test2文件夹 &#xff0c;然后我们在vscode中打开该文件夹 然后我们打开j…

C++教学——从入门到精通 5.单精度实数float

众所周知&#xff0c;三角形的面积公式是(底*高)/2 那就来做个三角形面积计算器吧 到吗如下 #include"bits/stdc.h" using namespace std; int main(){int a,b;cin>>a>>b;cout<<(a*b)/2; } 这不对呀&#xff0c;明明是7.5而他却是7&#xff0c;…

(一)kafka实战——kafka源码编译启动

前言 本节内容是关于kafka消息中间键的源码编译&#xff0c;并通过idea工具实现kafka服务器的启动&#xff0c;使用的kafka源码版本是3.6.1&#xff0c;由于kafka源码是通过gradle编译的&#xff0c;以及服务器是通过scala语言实现&#xff0c;我们要预先安装好gradle编译工具…

暴力破解笔记

1 暴力破解简介 暴力破解&#xff1a; 蛮力攻击&#xff0c;又称为穷举攻击&#xff0c;或暴力破解&#xff0c;将密码进行逐个尝试验证&#xff0c;直到尝试出真正的密码为止。 暴力破解是指采用反复试错的方法并希望最终猜对&#xff0c;以尝试破解密码或用户名或找到隐藏的…

进无止境,砥砺前行,互联网营销专家杨建允助力多个品牌和机构提升营运效率!

进无止境&#xff0c;砥砺前行&#xff01;在过去的一年&#xff08;2023年&#xff09;&#xff0c;互联网营销专家杨建允持续为数十家品牌和机构提供了品牌和营销支持&#xff01;统计如下&#xff1a;&#xff08;排名不分先后&#xff09; 滴滴&#xff1b; 企查查&#…

了解XSS和CSRF攻击与防御

什么是XSS攻击 XSS&#xff08;Cross-Site Scripting&#xff0c;跨站脚本攻击&#xff09;是一种常见的网络安全漏洞&#xff0c;它允许攻击者在受害者的浏览器上执行恶意脚本。这种攻击通常发生在 web 应用程序中&#xff0c;攻击者通过注入恶意脚本来利用用户对网站的信任&…

属性选择器

1.[title]{background:yellow;}&#xff1a;所有带title标签设置成黄色 2.div[class]{background:yellow;}&#xff1a;所有div中带class标签设置成黄色 3.div[classbox1]{border:1px solid blue; }&#xff1a;div中包含class并且classbox1的设置成蓝边框 4. class…

【Linux】进程实践项目 —— 自主shell编写

送给大家一句话&#xff1a; 不管前方的路有多苦&#xff0c;只要走的方向正确&#xff0c;不管多么崎岖不平&#xff0c;都比站在原地更接近幸福。 —— 宫崎骏《千与千寻》 自主shell命令编写 1 前言2 项目实现2.1 创建命令行2.2 获取命令2.3 分割命令2.4 运行命令 3 源代码…

python mysql错误如何处理

错误代码类型&#xff1a;pymysql.err.InternalError: (1054, "Unknown column jack in field list") import pymysql d_mysql {host: 127.0.0.1, port: 33333,user: *****,password: *****,db: *****,charset: utf8} conn pymysql.connect(**d_mysql) cur co…

基于SSM远程同步课堂系统

基于SSM远程同步课堂系统的设计与实现 摘要 在这样一个网络数据大爆炸的时代&#xff0c;人们获取知识、获取信息的通道非常的多元化&#xff0c;通过网络来实现数据信息的获取成为了现在非常常见的一种方式&#xff0c;而通过网络进行教学&#xff0c;在网络上进行远程的课堂…

C++--内联函数

当调用一个函数时&#xff0c;程序就会跳转到该函数&#xff0c;函数执行完毕后&#xff0c;程序又返回到原来调用该函数的位置的下一句。 函数的调用也需要花时间&#xff0c;C中对于功能简单、规模小、使用频繁的函数&#xff0c;可以将其设置为内联函数。 内联函数&#xff…

IAG—热门单曲

喜欢你&#x1f60d; 泡沫&#x1fae7; 倒数 ... 太多了 句号 多远都要在一起 来自天堂的魔鬼 再见 ……

车载电子电器架构 —— 通信信号数据库开发

车载电子电器架构 —— 信号数据库开发 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自…

芒果YOLOv8改进130:Neck篇,即插即用,CCFM重构跨尺度特征融合模块,构建CCFM模块,助力小目标检测涨点

芒果专栏 基于 CCFM 的改进结构,改进源码教程 | 详情如下🥇 💡本博客 改进源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 即插即用 结构。博客 包括改进所需的 核心结构代码 文件 YOLOv8改进专栏完整目录链接:👉 芒果YOLOv8深度改进教程 | 🔥 订阅一个…

TCP通信——端口转发(重点内容)

实现多人群聊 Client(客户端&#xff09;建立通信 package com.zz.tcp.case1;import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner;public class Client {public static void mai…

论文笔记:GPT-4 Is Too Smart To Be Safe: Stealthy Chat with LLMs via Cipher

ICLR 2024 reviewer评分 5688 1 论文思路 输入转换为密码&#xff0c;同时附上提示&#xff0c;将加密输入喂给LLMLLM输出加密的输出加密的输出通过解密器解密 ——>这样的步骤成功地绕过了GPT-4的安全对齐【可以回答一些反人类的问题&#xff0c;这些问题如果明文问的话&…

Linux(CentOS 7 )基于git、maven实现springboot自动化部署

前提 1、已安装git、maven、java环境 不清楚的可以看另一篇文章&#xff1a; https://blog.csdn.net/weixin_44646763/article/details/137041469 2、已为项目设置远程 git 仓库 origin (可以通过&#xff1a;git remote add origin https://github.com/xxx/xxx.git设置) 创…

【Linux】详解软硬链接

一、软硬链接的建立方法 1.1软链接的建立 假设在当前目录下有一个test.txt文件&#xff0c;要对其建立软链接&#xff0c;做法如下&#xff1a; ln就是link的意思&#xff0c;-s表示软链接&#xff0c;test.txt要建立软链接的文件名&#xff0c;后面跟上要建立的软链接文件名…

设计模式深度解析:AI如何影响装饰器模式与组合模式的选择与应用

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL应用》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 AI如何影响装饰器模式与组合模式的选择与应用 在今天这个快速发展的技术时代&#…