当前位置: 首页 > news >正文

虚拟列表 - Vue3实现一个可动态改变高度的虚拟滚动列表

虚拟列表 - Vue3实现一个可动态改变高度的虚拟滚动列表

前言

在开发中经常遇到大量的渲染列表数据问题,往往我们就只是简单地遍历渲染,没有过多地去关注是否会存在性能问题,这导致如果数据量较大的时候,比如上万条数据,将会在dom中渲染上万个节点,这将加大浏览器的开销,可能会导致页面卡顿,加载慢等性能问题。因此,在渲染大量数据时,可以选择使用虚拟列表,只渲染用户可视区域内的dom节点。该组件已开源上传npm,可以直接安装使用,Git地址在文尾。

虚拟列表实现原理

每条固定高度

1、通过传入组件的每条数据的高度,计算整个列表的高度,从而得到滚动列表的总高,并将总高赋值给列表。
2、监听滚动事件,监听外层容器的滚动事件,并确定可视区域内起止数据在总数据的索引值,这可以通过scrollTop来实现。
3、设置数据对应的元素,为每条数据设置一个绝对定位,其中top等于索引值乘以每条数据的高度。
4、考虑缓冲条数,为了避免滑动过快产生空白,可以设置缓冲条数。具体来说,如果滚动到底部,可以只显示最后N条数据,如果滚动到上部,可以只显示前N条数据。
这样,就可以实现一个固定高度的虚拟列表。

每条动态高度

原理和固定高度基本一致,差别在于,用户可以预先定义每条数据的高度,在渲染时再动态获取每一条数据的实际高度,从而重新计算滚动列表的总体高度。

主要代码实现

模板部分

showItemList循环可视区域内的数据+缓存区的数据

<template><div class="virtual-wrap" ref="virtualWrap" :style="{width: width + 'px',height: height + 'px',}" @scroll="scrollHandle"><div class="virtual-content" :style="{height: totalEstimatedHeight +'px'}"><list-item v-for="(item,index) in showItemList" :key="item.dataIndex+index" :index="item.dataIndex" :data="item.data" :style="item.style"@onSizeChange="sizeChangeHandle"><template #slot-scope="slotProps"><slot name="slot-scope" :slotProps="slotProps"></slot></template></list-item></div></div>
</template>
获取需要渲染的数据

通过可视区域内的开始和结束索引,获取需要渲染的列表数据。

const getCurrentChildren = () => {//重新计算高度estimatedHeight(props.itemEstimatedSize,props.itemCount)const [startIndex, endIndex] = getRangeToRender(props, scrollOffset.value)const items = [];for (let i = startIndex; i <= endIndex; i++) {const item = getItemMetaData(i);const itemStyle = {position: 'absolute',height: item.size + 'px',width: '100%',top: item.offset + 'px',};items.push({style: itemStyle,data: props.data[i],dataIndex:i});}showItemList.value = items;
}
获取开始和结束索引
const getRangeToRender = (props: any, scrollOffset: any) => {const { itemCount } = props;const startIndex = getStartIndex(props, scrollOffset);const endIndex = getEndIndex(props, startIndex + props.buffCount);return [Math.max(0, startIndex -1),Math.min(itemCount - 1, endIndex ),];
};const getStartIndex = (props: any, scrollOffset: number) => {const { itemCount } = props;let index = 0;while (true) {const currentOffset = getItemMetaData(index).offset;if (currentOffset >= scrollOffset) return index;if (index >= itemCount) return itemCount;index++}
}const getEndIndex = (props: any, startIndex: number) => {const { height, itemCount } = props;// 获取可视区内开始的项const startItem = getItemMetaData(startIndex);// 可视区内最大的offset值const maxOffset = Number(startItem.offset) + Number(height);// 开始项的下一项的offset,之后不断累加此offset,知道等于或超过最大offset,就是找到结束索引了let offset = Number(startItem.offset) + startItem.size;// 结束索引let endIndex = startIndex;// 累加offsetwhile (offset <= maxOffset && endIndex < (itemCount - 1)) {endIndex++;const currentItem = getItemMetaData(endIndex);offset += currentItem.size;}// 更新已计算的项的索引值measuredData.lastMeasuredItemIndex = endIndex;return endIndex;
};
动态计算节点高度

const estimatedHeight = (defaultEstimatedItemSize = 50, itemCount: number) => {let measuredHeight = 0;const { measuredDataMap, lastMeasuredItemIndex } = measuredData;// 计算已经获取过真实高度的项的高度之和if (lastMeasuredItemIndex >= 0) {const lastMeasuredItem = measuredDataMap[lastMeasuredItemIndex];measuredHeight = lastMeasuredItem.offset + lastMeasuredItem.size;}// 未计算过真实高度的项数const unMeasuredItemsCount = itemCount - measuredData.lastMeasuredItemIndex - 1;// 预测总高度totalEstimatedHeight.value = measuredHeight + unMeasuredItemsCount * defaultEstimatedItemSize;
}

子组件实现

1、通过ResizeObserver在子节点高度变化时触发父组件的方法,重新计算整体高度。
2、通过插槽将每条数据动态插入到列表中。

<template><div :style="style" ref="domRef"><slot name="slot-scope" :data="data"></slot></div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue'const emit = defineEmits(['onSizeChange']);const props = defineProps({style: {type: Object,default: () => { }},data: {type: Object,default: () => { }},index: {type: Number,default: 0}
})const domRef = ref<any>(null);
const resizeObserver:any = null;onMounted(() => {const domNode = domRef.value.children[0];emit("onSizeChange", props.index, domNode);const resizeObserver = new ResizeObserver(() => {emit("onSizeChange", props.index, domNode);});resizeObserver.observe(domNode);
})onUnmounted(() => {if (resizeObserver) {resizeObserver?.unobserve(domRef.value.children[0]);}
})
</script>

组件使用

npm install @fcli/vue-virtually-list --save-dev 来安装在项目中使用
import VueVirtuallyList from '@fcli/vue-virtually-list';
const app=createApp(App)
app.use(VueVirtuallyList);

示例:


<div class="content"><vue-virtually-list :data="list" :height="400" :width="600" :itemCount="1000" :itemEstimatedSize="20" :buffCount="50"><template #slot-scope="{slotProps}"><div class="li">{{ slotProps.data.text }}</div></template></vue-virtually-list>
</div>
属性属性名称类型可选值
data列表数据Array[]
height虚拟容器的高度number0
width虚拟容器的宽度number0
itemCount滚动列表的条数number0
itemEstimatedSize预设每行数据的高度number可不填,组件会动态计算
buffCount上下缓冲区的条数number增加快速滚动时的流畅性
#slot-scope插槽 | object | slotProps.data|
slot

例:

  <template #slot-scope="{slotProps}"><div class="li">{{ slotProps.data.text }}</div></template>

Git地址:https://gitee.com/fcli/vue-virtually-list.git

相关文章:

虚拟列表 - Vue3实现一个可动态改变高度的虚拟滚动列表

虚拟列表 - Vue3实现一个可动态改变高度的虚拟滚动列表 前言 在开发中经常遇到大量的渲染列表数据问题&#xff0c;往往我们就只是简单地遍历渲染&#xff0c;没有过多地去关注是否会存在性能问题&#xff0c;这导致如果数据量较大的时候&#xff0c;比如上万条数据&#xff…...

PyTorch实战:实现Cifar10彩色图片分类

目录 前言 一、Cifar10数据集 class torch.utils.data.Dataset torch.utils.data.DataLoader 二、定义神经网络 普通神经网络: 定义损失函数和优化器 训练网络-Net CPU训练 模型准确率 ​编辑 GPU训练 训练网络-LeNet 模型准确率 点关注&#xff0c;防走丢&#x…...

Vue模板语法(下)

一.事件处理器 什么是事件处理器 建立一个HTML编写事件处理器 测试结果 二.表单的综合案例 什么是表单综合案例 建立一个HTML来编写表单案例 测试结果 三.局部组件 什么是组件通信 自定义组件 测试结果 组件通信-父传子 测试结果 组件通信-子传父 测试结果 一.事件…...

uniapp掉完接口后刷新当前页面方法

uniapp掉完接口后刷新当前页面方法 掉完接口&#xff0c;里面加下面这个方法uni.redirectTo({}) setTimeout(() > {uni.redirectTo({// 当前页面路由url: /pages/property/mutualrotation/mutualrotation);}, 500)实例 mutualRotationSubmit() {let self this;uni.showMod…...

linux安装redis超级详细教程

redis源码安装 安装gcc redis是C语言编写的&#xff0c;所以我们需要先在Linux上安装和升级&#xff0c;C语言的编译环境。 #安装gcc yum install -y gcc-c autoconf automake#centos7 默认的 gcc 默认是4.8.5,版本小于 5.3 无法编译,需要先安装gcc新版才能编译 gcc -v#升级…...

2023-09-20 事业-代号z-个人品牌-数据库内核专家-分析

摘要: 在个人品牌层面, 必然脱离不开技术本身, 而身为数据库内核专家, 让别人尽快感知到我的专家身份至关重要. 本文从过去的经历中分析和思考, 如何尽快以技术专家的身份被感知. 过去所见过的高管的技术特点: 不在一线处理具体的事情技术理论深厚, 广度非常厉害, 知道很多相…...

UVA-1343 旋转游戏 题解答案代码 算法竞赛入门经典第二版

GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版 题目其实不难&#xff0c;但是耗费了我较多时间。 这种题关键就是在于找到约束条件&#xff0c;我在DFS的基础上&#xff0c;试了很多种策略&#xff1a; 1. 对3种数字&#xff0c;每种数字…...

【运维篇】二、配置文件与多环境控制

文章目录 1、临时属性2、IDEA中的临时属性3、配置文件4级分类4、关于四级分类的思考5、自定义配置文件6、多环境开发&#xff08;yaml版&#xff09;7、配置文件按环境分类8、include与group再细粒度9、一点思考10、多环境开发兼容问题 1、临时属性 jar包或者镜像已经打完了&a…...

【WFA】 VHT-5.2.27 Pre-requisite throughput lower than expected

先看仪表log,可以看到log中只有0.00346666666667Mbps,说明了速率很低 ~~~~~ Storing throughput ~~~~~ Mon, 11 Sep 2023 13:13:06 INFO strmTimeStampList2 count 1 Mon, 11 Sep 2023 13:13:06 INFO Storing $X1 = 0.00346666666667 [Mbps] Mon, 11 Sep 2023 13:13:…...

Pytorch史上最全torch全版本离线文件下载地址大全(9月最新)

以下为pytorch官网的全版本torch文件离线下载地址 torch全版本whl文件离线下载大全https://download.pytorch.org/whl/torch/其中的文件版本信息如下所示&#xff08;部分版本信息&#xff0c;根据需要仔细寻找进行下载&#xff09;&#xff1a;...

CentOS服务器利用docker搭建中间件命令集合

一、挂载服务器磁盘 #挂盘语句 fdisk /dev/vdb 在分别输入n、p、1、2048、1048575999、w mkfs.ext4 /dev/vdb mkdir /data echo /dev/vdb /data ext4 defaults 0 0 >> /etc/fstab mount -a df -hfirewall-cmd --zonepublic --add-port8002/tcp --permanent firewall-c…...

Flask狼书笔记 | 09_图片社交网站 - 长文

文章目录 9 图片社交网站9.1 项目组织架构9.2 编写程序骨架9.3 高级用户认证9.4 基于用户角色的权限管理9.5 使用Flask-Dropzone优化文件上传9.6 使用Flask-Avatars处理用户头像9.7 图片展示与管理9.8 收藏图片9.9 用户关注9.10 消息提醒9.11用户资料与账户设置9.12 首页与探索…...

【链表】K 个一组翻转链表-力扣 25 题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…...

jdk17新特性

JDK17新特性 jdk17下载地址&#xff1a;https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe JDK 17 文档 - 首页 (oracle.com) 垃圾回收器&#xff08;Z Garbage Collector&#xff09; 概述 JDK17引入名为ZGC&#xff08;Z Garbage Collector&#x…...

爬虫项目(四):抓取网页所有图片

文章目录 一、书籍推荐二、完整代码三、运行结果 一、书籍推荐 推荐本人书籍《Python网络爬虫入门到实战》 &#xff0c;详细介绍见&#x1f449;&#xff1a; 《Python网络爬虫入门到实战》 书籍介绍 二、完整代码 原理&#xff1a;抓取该链接中所有的图片格式。基于seleni…...

短剧推广和小说推文在哪里授权介绍

短剧推广和小说推文都属于很热门的赛道&#xff0c;都可以通过“巨量推文”进行授权 在巨量推文找到想推广的小说或者短剧后申请推广即可&#xff0c;小说需要有回填作品信息&#xff0c;短剧为全自动&#xff0c;出数据后实时同步到平台...

Java:本地文件通过表单参数接口发送后大小变成0

问题 发现一个文件生成以后&#xff0c;如果不通过接口发送&#xff0c;大小就正常&#xff0c;通过接口发送&#xff0c;文件大小就变成0了&#xff0c;发送的文件也是0 空文件 代码 MultiValueMap<String, Object> form new LinkedMultiValueMap<>();FileSyst…...

Linux 共享内存

#include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg);功能&#xff1a;创建一个新的内存段或者获得一个既有的共享内存段的标识。新创建的内存段中的数据都会被初始化为0参数&#xff1a;-key&#xff1a;key_t类型是一个整…...

druid在springboot中如何整合配置!

在Spring Boot中配置Druid作为数据源非常简单。Druid是一个高性能的数据库连接池&#xff0c;它提供了丰富的监控和统计功能&#xff0c;适用于各种数据库。以下是在Spring Boot中配置Druid数据源的步骤&#xff1a; 1. 添加Druid依赖&#xff1a; 首先&#xff0c;您需要在项…...

数据结构:栈

文章目录 栈一&#xff0c;概述二&#xff0c;添加数据三&#xff0c;删除数据 栈 一&#xff0c;概述 栈&#xff08;Stack&#xff09;是一种特殊的线性表&#xff0c;它只允许在一端进行插入和删除操作&#xff0c;通常被称为“后进先出”&#xff08;Last In First Out&a…...

每日刷题-6

目录 一、选择题 二、算法题 1.Fibonacci数列 2.合法括号序列判断 一、选择题 1、 解析&#xff1a;内联函数是一种可以提高函数执行效率的方法&#xff0c;它的原理是编译时在函数调用点直接展开函数体的代码&#xff0c;从而避免了函数调用的开销。 但是&#xff0c;内联函…...

systrace使用注意事项

打开systrace文件报错&#xff1a;Unable to select a master clock domain because no path can be found from “SYSTRACE” to “LINUX_FTRACE_GLOBAL”. 使用systrace生成的trace.html文件无法打开&#xff0c;或者报上面的错误&#xff0c;可以选择下面这个方式&#xff1…...

RockyLinux9.2 网卡配置和nmcli、nmtui命令的使用

NetworkManager NetworkManager 是一个标准的Linux网络配置工具套件&#xff0c;支持服务器&#xff0c;也支持桌面环境&#xff0c; 发展到如今&#xff0c;绝大多数流行的发行版都支持它。 这套网络配置工具适用于 Rocky Linux 8 及更高版本。 nmcli是nm的命令行工具、nmt…...

Java线程池ThreadPoolExecutor应用(Spring Boot微服务)

记录&#xff1a;475 场景&#xff1a;在Spring Boot微服务中使用Java线程池ThreadPoolExecutor。实现Runnable接口提交线程任务到线程池。 版本&#xff1a;JDK 1.8,Spring Boot 2.6.3。 1.使用注解配置线程池ThreadPoolExecutor (1)说明 ThreadPoolExecutor&#xff0c;…...

QT5|C++|通过信号槽机制实现进度条更新

背景&#xff1a;最近在写一个删除90天数据显示进度的功能&#xff0c;实现思路是&#xff1a;通过信号槽捕获当前进度值实现。 备注&#xff1a;点击start按钮&#xff0c;开始更新进度条&#xff0c;直到100&#xff08;每隔1s进行更新&#xff09;举个栗子&#xff1a; 1、…...

什么是智能推荐?智能推荐的原理是什么?

一、智能推荐的魔力 2020年的愚人节晚间&#xff0c;罗永浩在抖音带货&#xff0c;相信你也被刷屏了吧。3小时的直播过程中&#xff0c;22款产品轮番出场&#xff0c;最终首播支付交易总额突破1.1亿、整场直播观看总人数超过4800万、总销售件数逾91万&#xff0c;粉丝打赏音浪…...

Windows下的Elasticsearch-head安装

Windows下的Elasticsearch-head安装 参考&#xff1a;https://gitcode.net/mirrors/mobz/elasticsearch-head 需要用到 npm 命令&#xff0c;这里可以提前下载安装下Node.js 即可自动安装npm&#xff1b; Node.js 下载安装地址&#xff1a;https://nodejs.org/en/download # 进…...

两台服务器间进行文件传输

目录 方法1&#xff1a;使用SCP 方法2&#xff1a;使用rsync 使用SSH密钥 两台服务器之间进行文件传输通常可以使用SCP&#xff08;Secure Copy Protocol&#xff09;或rsync命令。这两种方法都是在UNIX和Linux系统上常用的工具&#xff0c;用于安全地复制文件和目录。以下是…...

研究生选控制嵌入式还是机器视觉好?

研究生选控制嵌入式还是机器视觉好&#xff1f; 我是嵌入式/硬件方向转的算法&#xff0c;现在是公司的算法负责人&#xff0c;如果再让我选一次&#xff0c;我是不会再选嵌入式方 向&#xff0c;嵌入式如果只做技术是没前途的。 你要是有一定自学能力&#xff0c;能自己在学校…...

SecureCRT SSH与FTP连接中文乱码

1、首先要保证服务端环境变量是UTF-8编码的 LANG”zh_CN.UTF-8″ 2、会话里面配置好字符编码&#xff1a;UTF-8 SSH会话的窗口就可以正常显示中文了&#xff0c;效果如下 3、打开FTP或者SFTP时进行文件传输时&#xff0c;列表窗口里面还是乱码&#xff0c;需要把SecureCRT安…...

中国建设网官方网站下载e路最新版官方/郑州网站建设推广有限公司

事件流处理 事件流处理&#xff08;Event Stream Processing&#xff0c;ESP&#xff09;和复杂事件处理&#xff08;Complex Event Processing&#xff0c;CEP&#xff09;的系统&#xff0c;它可以监测事件流并当特定事件发生时触发某些行动——可看作是把数据库反过来&#…...

制作流程图的网站/湖南百度推广公司

实现虚拟化的方法不止一种&#xff0c;各种方法都可以通过不同层次的抽象来实现相同的结果。本文将给大家介绍Linux中常用的4种虚拟化方法&#xff0c;以及它们相应的优缺点。业界有时会使用不同的术语来描述相同的虚拟化方法。(1)硬件仿真。毫无疑问&#xff0c;最复杂的虚拟化…...

天津网站建设费用/萝卜建站

一、情景描述&#xff1a; 后台给一个txt文件&#xff0c;编码是utf-8,在Mac电脑Xcode开发环境下读取txt文件内容&#xff0c;汉字会出现乱码&#xff0c;英文没有乱码这种情况。 二、尝试解决方法&#xff1a; 修改编码格式&#xff0c;尝试了NSUTF16StringEncoding,NSUTF8Str…...

备案用网站建设方案/英文网站seo发展前景

由于公司业务比较多&#xff0c;部署的站点也比较多。为了网站安全运行&#xff0c;以防故障发生时能第一时间知晓&#xff0c;特意编写下面监控脚本&#xff0c;对网站访问状态和超时时间进行监控&#xff1a;当code状态为5xx或者访问超时时间大于10s时进行报警。脚本脚本如下…...

网易企业邮箱登录页/安徽网站seo公司

在第2部分中&#xff0c;我将向您介绍如何使用Exchange Server中提供的新cmdlet导入/导出数据&#xff0c;以及如何查看导入和导出的信息统计信息这样做。走起&#xff01;将数据从PST文件导入到邮箱现在是时候尝试使用New-MailboxImportRequest cmdlet 将数据从PST文件导入Exc…...

php在网站制作中的运行机制/百度网络营销中心app

1.创建项目屏幕快照 2018-12-14 23.22.23.png2.添加依赖项屏幕快照 2018-12-14 23.23.55.png屏幕快照 2018-12-14 23.24.24.png3.添加数据库字符串在appsetting.json中添加数据库信息"DefaultDbConnect": "serverlocalhost;databasedemo;userroot;password12345…...