前端: 如何优化列表大批量的数据渲染

news/2025/10/21 8:09:44/文章来源:https://www.cnblogs.com/Dsir/p/19154048

需求点:如何列表数据渲染进行优化?

最近业务上也碰到这个问题点。上网也查了查资料,貌似也经常问,特此写文章记录下来。

关于如何处理以上上面的业务痛点:
就两点:
1 、虚拟列表是最主流的解决方案,不渲染所有的数据,只渲染可视区域中的数据。当用户滑(滚)动时,通过监听 scroll 来判断是上滑还是下拉,从而更新数据。同理 IntersectionObserver 和 getBoundingClientRect 都能实现
2、时间分片主要是分批渲染DOM,使用 requestAnimationFrame 来让动画更加流畅
tips: 第二点就不详细讲述了,文末有链接对应,可自行享用。

话不多说直接上代码:不懂的可下方评论或者私信:

<template><divref="list":style="{height}"class="infinite-list-container"@scroll="scroll($event)"><divref="phantom"class="infinite-list-phantom"/><divref="content"class="infinite-list"><div><divv-for="item in visibleData"ref="items":id="item._index":key="item._index"class="infinite-list-item"><!-- <slot ref="slot" :item="item.item"></slot> --><p><span style="color:red">{{ item.id }}</span>{{ item.value }}</p></div></div></div></div>
</template>
<script>
export default {props: {/** 需要渲染的数据 */listData: {type: Array,default: () => []},/** 每项高度 */itemSize: {type: Number,default: 200},/** 视口高度 */height: {type: String,default: '100%'}},data() {return {screenHeight: 0, // 可视区域高度startOffset: 0, // 偏移量start: 0, // 起始索引end: null // 结束索引};},computed: {/** 列表总高度 */listHeight() {return this.listData.length * this.itemSize;},/** 可显示的列表项数 */visibleCount() {return Math.ceil(this.screenHeight / this.itemSize);},/** 偏移量对应的style */getTransform() {return `transform3d(0, ${this.startOffset}px, 0)`;},/** 可显示列表数据 */visibleData() {return this.listData.slice(this.start, Math.min(this.end, this.listData.length));}},mounted() {this.screenHeight = this.$el.clientHeight;this.start = 0;this.end = this.start + this.visibleCount;},created() {this.initPositions();},updated() {this.$nextTick(function() {if (!this.$refs.items || !this.$refs.items.length) {return;}// 获取真实元素大小,修改对应的尺寸缓存this.updateItemsSize();// 更新列表总高度let height = this.positions[this.positions.length - 1].bottom;this.$refs.phantom.style.height = height + 'px';// 更新真实偏移量this.setStartOffset();});},methods: {/** 滚动事件 */scroll(e) {// 当前滚动位置let scrollTop = this.$refs.list.scrollTop;// 此时的开始索引this.start = this.getStartIndex(scrollTop);// 此时的结束索引this.end = this.start + this.visibleCount;// 此时的偏移量this.setStartOffset();},initPositions() {this.positions = this.listData.map((d, index) => ({index,height: this.estimatedItemSize,top: index * this.estimatedItemSize,bottom: (index + 1) * this.estimatedItemSize}));},/** 获取列表起始索引 */getStartIndex(scrollTop = 0) {return this.binarySearch(this.positions, scrollTop);},/** 二分查找 */binarySearch(list, value) {let start = 0;let end = list.length - 1;let tempIndex = null;while (start <= end) {let midIndex = parseInt((start + end) / 2);let midValue = list[midIndex].bottom;if (midValue === value) {return midIndex + 1;} else if (midValue < value) {start = midIndex + 1;} else if (midValue > value) {if (tempIndex === null || tempIndex > midIndex) {tempIndex = midIndex;}end = end - 1;}}return tempIndex;},/** 获取当前列表项的当前尺寸 */updateItemsSize() {let nodes = this.$refs.items;nodes.forEach(node => {let rect = node.getBoundingClientRect();let height = rect.height;let index = +node.id.slice(1);let oldHeight = this.positions[index].height;let dValue = oldHeight - height;// 存在差值if (dValue) {this.positions[index].bottom = this.positions[index].bottom - dValue;this.positions[index].height = height;for (let k = index + 1; k < this.positions.length; k++) {this.positions[k].top = this.positions[k - 1].bottom;this.positions[k].bottom = this.positions[k].bottom - dValue;}}});},/** 获取当前位置的便宜量 */setStartOffset() {let startOffset = this.start >= 1 ? this.positions[this.start - 1].bottom : 0;this.$refs.content.style.transform = `translate3d(0,${startOffset}px,0)`;}}
};
</script><style lang="less" scoped>
.infinite-list-container {overflow: auto;position: relative;-webkit-overflow-scrolling: touch;
}.infinite-list-phantom {position: absolute;left: 0;top: 0;right: 0;z-index: -1;
}.infinite-list {left: 0;right: 0;top: 0;position: absolute;
}.infinite-list-item {padding: 5px;color: #555;box-sizing: border-box;border-bottom: 1px solid #999;
}
</style>

这几篇文章讲述的很详细还有对应效果:
link
link2

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

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

相关文章

量子计算25年发展历程与技术挑战

本文回顾了量子信息处理会议25年发展历程,探讨了量子计算从理论到实验的突破,包括量子算法实现、量子复杂性理论对数学的影响,以及当前面临的可扩展性、错误率控制和实际应用等关键技术挑战。25年量子信息处理发展历…

tomcat启动一次问题的处理。

tomcat启动一次问题的处理。说明:2025.10.20,出现启动tomcat对任何请求都没有响应的情况。通过删除 $tomcat/work/Catalina 下的全部数据。并重启解决。但是重启需要的时间比较久。大约5分钟。

软件开发 --- trae如何和环境配合执行

软件开发 --- trae如何和环境配合执行trae会自动执行代码,但是执行前需要我们提前安装好所有的执行环境。 有的环境可能需要手动配合,比如trae在执行这个代码前手动触发环境执行。

marmot的一些特点

marmot的一些特点以前简单介绍过marmot ,以下说下一些特点 特点当前版本已经通过nats server 包内置到了服务中,不需要独立部署nats 了,但是推荐还是部署3个节点 默认内置的nats 没有开启认证,注意使用,同时nats …

应用安全 --- 如何反编译一个超大的函数

应用安全 --- 如何反编译一个超大的函数先用ida反编译一下 再用claude max 完善代码并配合完整的提示词 再次执行上述过程直到没有任何遗漏的代码

藏宝阁

书籍轻松主义★★★★☆反脆弱★★★★★娱乐至死★★★★☆动物庄园★★★★★谈谈方法★★★★☆小说雪中悍刀行★★★★★剑来★★★★★斗破苍穹★★★★★完美世界★★★★★武动乾坤★★★☆☆我在精神病院学斩神…

【模块化解读】commonjs vs commonjs2 exports vs module.exports

背景 最近在用typescript写工具库的时候,无意中在 webpack中看到了两个关键字,commonjs 和 commonjs2. 瞬间产生了好奇。后面看了issues才得知它们与模块化 导出有着密切关系。 CommonJs spec defines only exports.…

【GitHub每日速递 251021】一键将全新Arch安装变身超美现代Web开发系统!Omarchy太神了

原文: https://mp.weixin.qq.com/s/aE_bPqSXRQxxH7zq_4HYIQ 一键将全新Arch安装变身超美现代Web开发系统!Omarchy太神了 omarchy 是一个基于 Arch Linux 和 Hyprland 桌面环境的自动化配置工具。简单讲,它是一套预设…

[Mongodb]mongodb的安装以及增删改查

mongodb的安装 mongo主页 下载完成之后将目录放置下方 /usr/local/安装之后就配置环境变量: vim ~/.bash_profile下方是我自己的环境变量配置 # JDK_HOMEJAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_321.j…

PHP 8.5 新特性 闭包可以作为常量表达式了

PHP 8.5 新特性 闭包可以作为常量表达式了 PHP 8.5 又带来了一个让人兴奋的新特性:闭包现在可以作为常量表达式使用了,这意味着它们可以出现在默认参数或属性值中。 你是不是也遇到过这种情况:想在 PHP 中把闭包设置为…

【JavaScript-基础】split,splice,slice 三者的用法

split,splice,slice 三者的用法 很多知识点不熟悉可以自行去下面链接查询: mdn web docs 最近一直忙于搞python,等后续有时间更新python相关的内容。毕竟现在在弄web.有些知识点需要巩固,以便自己后续带人和巩固自己…

2025 代码源 CSP-S 模拟赛复盘

Day 16 T1 双重心 分类讨论一下:是原树的双重心之一,考虑把这条边割掉,接到另一个连通块的任意一个点上都是可行的。 不割掉原树上的双重心的边,两侧的连通块内的的任意一条边可以断开,连通块内相互连边就行。 考…

2025.10.21——1绿

普及+/提高 P1347 排序 wpmx昨晚写的有意思的题,数据范围比较小,我就直接用set+m次拓扑排序,30min写出来,要注意输出顺序后的句号,以及特判n==1

【JavaScript-基础】map、forEach、for、for in、for of等的区别

tips:循环虽好,大家都得按自己所需场景进行使用。个人建议,不喜勿喷 forEach forEach: forEach(item,index,array), item:当前处理的数据,index:下标, array:整个数组 遍历全部数据,不能通过return结束循环,消耗…

dotnet 利用 Windows 注册表实现开机自动启动

本文记录一个开机自动启动实现方法,通过写入到注册表实现开机之后,用户登录完成之后让应用程序开机自启本文将演示写入 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run 注册表路线,实现应用程序…

帮我回答这些问题

◦ 以太坊交易的数据结构及EIP1559/712协议的理解。 ◦ 以太坊的账⼾是如何⽣产的,公私钥的关系。 ◦ 以太坊区块链浏览器⼀般会展⽰哪些信息,⼤概能知道。 ◦ 以太坊交易nonce的作⽤,nonce异常交易如何处理。 ◦ 以…

使用uWSGI和Nginx部署深度学习模型指南

本文详细介绍了如何通过uWSGI应用服务器和Nginx反向代理将深度学习模型部署为可扩展的Web服务,涵盖WSGI协议原理、服务器配置步骤及性能优化要点,帮助构建高并发生产级AI应用。如何使用uWSGI和Nginx部署深度学习模型…

Python 类属性的应用场景

Python 类属性的应用场景 在面向对象编程中,类属性作为一种特殊的属性形式,始终扮演着“共享者”与“管理者”的角色。与实例属性为每个对象单独存储数据不同,类属性属于类本身,被所有实例共同拥有和访问。这种特性…

快速提升Entra ID安全性的实用指南

本文详细介绍了如何通过配置用户默认设置、保护特权角色、管理条件访问策略等关键步骤,快速提升Microsoft Entra ID的安全性,帮助企业构建更强大的云身份防护体系。快速提升Entra ID安全性 在2025年10月的BSides北弗…

为什么很多人分不清关联和聚合?

为什么很多人分不清关联和聚合 这个问题确实很常见,很多人(包括有经验的开发者)都会混淆关联和聚合。让我从多个角度分析这个现象的原因。 主要混淆原因 1. 代码实现的高度相似性 # 关联关系的代码 class Universit…