vue+element-ui el-table组件二次封装实现虚拟滚动,解决数据量大渲染DOM过多而卡顿问题

一、此功能已集成到TTable组件中

二、最终效果

在这里插入图片描述

三、需求

某些页面不做分页时,当数据过多,会导致页面卡顿,甚至卡死

四、虚拟滚动

一、固定一个可视区域的大小并且其大小是不变的,那么要做到性能最大化就需要尽量少地渲染 DOM 元素,而这个最小值也就是可视范围内需要展示的内容,而可视区域之外的元素均可以不做渲染。
二、如何计算可视区域内需要渲染的元素,我们通过如下几步来实现虚拟滚动:

1、每一行的高度需要相同,方便计算。
2、需要知道渲染的数据量(数组长度),可基于总量和每个元素的高度计算出容器整体的所需高度,这样就可以伪造一个真实的滚动条。
3、获取可视区域的高度。
4、在滚动事件触发后,滚动条的距顶距离即这个数据量中的偏移量,再根据可视区域本身的高度,算出本次偏移量,这样就得到了需要渲染的具体数据

五、具体实现(源码)

<template><div class="t-table" id="t_table"><el-tableref="el-table":data="tableData":class="{cursor: isCopy,row_sort: isRowSort,highlightCurrentRow: highlightCurrentRow,radioStyle: table.firstColumn && table.firstColumn.type === 'radio',treeProps: isShowTreeStyle,is_sort_icon:onlyIconSort}":max-height="useVirtual?maxHeight||540:maxHeight"v-bind="$attrs"v-on="$listeners":highlight-current-row="highlightCurrentRow":border="table.border || isTableBorder":span-method="spanMethod || objectSpanMethod":cell-class-name="cellClassNameFuc"@sort-change="soltHandle"@row-click="rowClick"@cell-dblclick="cellDblclick"><!-- 主体内容 --><template v-for="(item, index) in renderColumns"><el-table-columnv-if="item.isShowCol === false ? item.isShowCol : true":key="index + 'i'":type="item.type":label="item.label":prop="item.prop":min-width="item['min-width'] || item.minWidth || item.width":sortable="item.sort || sortable":align="item.align || 'center'":fixed="item.fixed":show-overflow-tooltip="useVirtual?true:item.noShowTip?false:true"v-bind="{ ...item.bind, ...$attrs }"v-on="$listeners"><template slot-scope="scope">...</template></el-table-column></template></el-table></div>
</template><script>
export default {name: 'TTable',props: {// table所需数据table: {type: Object,default: () => {return {}}// required: true},// 表头数据columns: {type: Array,default: () => {return []}// required: true},...// Table最大高度maxHeight: {type: [String, Number]},// 是否开启虚拟列表useVirtual: {type: Boolean,default: false}},data() {return {tableData: this.table?.data,/*** 虚拟列表*/saveDATA: [], // 所有数据tableRef: null, // 设置了滚动的那个盒子tableWarp: null, // 被设置的transform元素fixLeft: null, // 固定左侧--设置的transform元素fixRight: null, // 固定右侧--设置的transform元素tableFixedLeft: null, // 左侧固定列所在的盒子tableFixedRight: null, // 右侧固定列所在的盒子scrollTop: 0,scrollNum: 0, // scrollTop / (itemHeight * pageList)start: 0,end: 30, // 3倍的pageListstarts: 0, // 备份ends: 30, // 备份pageList: 10, // 一屏显示itemHeight: 48 // 每一行高度}},watch: {'table.data': {handler(val) {if (this.useVirtual) {this.saveDATA = valthis.tableData = this.saveDATA.slice(this.start, this.end)} else {this.tableData = val}},deep: true // 深度监听},scrollNum(newV) {// 因为初始化时已经添加了3屏的数据,所以只有当滚动到第3屏时才计算位移量if (newV > 1) {this.start = (newV - 1) * this.pageListthis.end = (newV + 2) * this.pageListrequestAnimationFrame(() => {// 计算偏移量this.tableWarp.style.transform = `translateY(${this.start *this.itemHeight}px)`if (this.fixLeft) {this.fixLeft.style.transform = `translateY(${this.start *this.itemHeight}px)`}if (this.fixRight) {this.fixRight.style.transform = `translateY(${this.start *this.itemHeight}px)`}this.tableData = this.saveDATA.slice(this.start, this.end)})} else {requestAnimationFrame(() => {this.tableData = this.saveDATA.slice(this.starts, this.ends)this.tableWarp.style.transform = `translateY(0px)`if (this.fixLeft) {this.fixLeft.style.transform = `translateY(0px)`}if (this.fixRight) {this.fixRight.style.transform = `translateY(0px)`}})}}},created() {// 是否开启虚拟列表if (this.useVirtual) {this.init()}},mounted() {// 是否开启虚拟列表if (this.useVirtual) {this.initMounted()}},methods: {initMounted() {this.$nextTick(() => {// 设置了滚动的盒子this.tableRef = this.$refs['el-table'].bodyWrapper// 左侧固定列所在的盒子this.tableFixedLeft = document.querySelector('.el-table .el-table__fixed .el-table__fixed-body-wrapper')// 右侧固定列所在的盒子this.tableFixedRight = document.querySelector('.el-table .el-table__fixed-right .el-table__fixed-body-wrapper')/*** fixed-left | 主体 | fixed-right*/// 创建内容盒子divWarpPar并且高度设置为所有数据所需要的总高度let divWarpPar = document.createElement('div')// 如果这里还没获取到saveDATA数据就渲染会导致内容盒子高度为0,可以通过监听saveDATA的长度后再设置一次高度divWarpPar.style.height = this.saveDATA.length * this.itemHeight + 'px'// 新创建的盒子divWarpChildlet divWarpChild = document.createElement('div')divWarpChild.className = 'fix-warp'// 把tableRef的第一个子元素移动到新创建的盒子divWarpChild中divWarpChild.append(this.tableRef.children[0])// 把divWarpChild添加到divWarpPar中,最把divWarpPar添加到tableRef中divWarpPar.append(divWarpChild)this.tableRef.append(divWarpPar)// left改造let divLeftPar = document.createElement('div')divLeftPar.style.height = this.saveDATA.length * this.itemHeight + 'px'let divLeftChild = document.createElement('div')divLeftChild.className = 'fix-left'this.tableFixedLeft &&divLeftChild.append(this.tableFixedLeft.children[0])divLeftPar.append(divLeftChild)this.tableFixedLeft && this.tableFixedLeft.append(divLeftPar)// right改造let divRightPar = document.createElement('div')divRightPar.style.height = this.saveDATA.length * this.itemHeight + 'px'let divRightChild = document.createElement('div')divRightChild.className = 'fix-right'this.tableFixedRight &&divRightChild.append(this.tableFixedRight.children[0])divRightPar.append(divRightChild)this.tableFixedRight && this.tableFixedRight.append(divRightPar)// 被设置的transform元素this.tableWarp = document.querySelector('.el-table .el-table__body-wrapper .fix-warp')this.fixLeft = document.querySelector('.el-table .el-table__fixed .el-table__fixed-body-wrapper .fix-left')this.fixRight = document.querySelector('.el-table .el-table__fixed-right .el-table__fixed-body-wrapper .fix-right')this.tableRef.addEventListener('scroll', this.onScroll)})},// 初始化数据init() {this.saveDATA = this.table?.datathis.tableData = this.saveDATA.slice(this.start, this.end)},// 滚动事件onScroll() {this.scrollTop = this.tableRef.scrollTopthis.scrollNum = Math.floor(this.scrollTop / (this.itemHeight * this.pageList))}}
}
</script>

六、源码地址

GitHub源码地址

Gitee源码地址

基于ElementUi或Antd再次封装基础组件文档

vue3+ts基于Element-plus再次封装基础组件文档

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

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

相关文章

使用ppt和texlive生成eps图片(高清、可插入latex论文)

一、说明 写论文经常需要生成高清的图片插入到论文中&#xff0c;本文以ppt画图生成高质量的eps图片的实现来介绍具体操作方法。关于为什么要生成eps图片&#xff0c;一个是期刊要求&#xff08;也有不要求的&#xff09;&#xff0c;另一个是显示图像的质量高。 转化获得eps…

Agile Management

Agile Management 敏捷管理

大数据学习06-Spark分布式集群部署

Spark完全分布式部署 前期准备&#xff0c;每台服务器都需要配置安装Scala下载Scala安装包配置环境变量 安装spark解压配置环境修改配置 前期准备&#xff0c;每台服务器都需要配置 配置好IP vim /etc/sysconfig/network-scripts/ifcfg-ens33 TYPE"Ethernet" PROX…

Facebook message tag 使用攻略

Messenger 讯息传不出去&#xff1f;无法发送FB 讯息给非好友&#xff1f; 2020年3月&#xff0c;Facebook 为了防止用户被过多的推广或垃圾讯息困扰而更新使用条款&#xff0c;现在商家要用FB传讯息给所有人&#xff08;包括非好友&#xff09;&#xff0c;应该使用 Facebook …

如何将Word转成PDF?试一下这个转换方法

Word转成PDF是现代办公中常见的需求&#xff0c;它可以确保文件的格式和内容在不同平台上保持一致&#xff0c;并且更加方便共享和打印。在这个数字化时代&#xff0c;我们经常需要将Word文档转换为PDF格式&#xff0c;无论是个人用户还是商务用户都会遇到这样的需求。那么如何…

[ 云计算 | AWS ] Java 应用中使用 Amazon S3 进行存储桶和对象操作完全指南

文章目录 一、前言二、所需 Maven 依赖三、先决必要的几个条件信息四、创建客户端连接五、Amazon S3 存储桶操作5.1. 创建桶5.2. 列出桶 六、Amazon S3 对象操作6.1. 上传对象6.2. 列出对象6.3. 下载对象6.4. 复制、重命名和移动对象6.5. 删除对象6.6. 删除多个对象 七、文末总…

企业数字化转型的关键技术有哪些?_光点科技

随着科技的不断进步和信息技术的快速发展&#xff0c;企业数字化转型已经成为保持竞争力和适应市场变化的关键举措。在这个数字化时代&#xff0c;企业需要借助先进的技术来优化业务流程、提升效率&#xff0c;以及更好地满足客户需求。以下是企业数字化转型过程中的关键技术。…

【机器学习】人工智能概述(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

华为云云服务器评测 | 从零开始:云耀云服务器L实例的全面使用解析指南

文章目录 一、前言二、云耀云服务器L实例要点介绍2.1 什么是云耀云服务器L实例2.1.1 浅析云耀云服务器L实例 2.2 云耀云服务器L实例的产品定位2.3 云耀云服务器L实例优势2.4 云耀云服务器L实例支持的镜像与应用场景2.5 云耀云服务器L实例与弹性云服务器&#xff08;ECS&#xf…

深度解析BERT:从理论到Pytorch实战

本文从BERT的基本概念和架构开始&#xff0c;详细讲解了其预训练和微调机制&#xff0c;并通过Python和PyTorch代码示例展示了如何在实际应用中使用这一模型。我们探讨了BERT的核心特点&#xff0c;包括其强大的注意力机制和与其他Transformer架构的差异。 关注TechLead&#x…

13.108.Spark 优化、Spark优化与hive的区别、SparkSQL启动参数调优、四川任务优化实践:执行效率提升50%以上

13.108.Spark 优化 1.1.25.Spark优化与hive的区别 1.1.26.SparkSQL启动参数调优 1.1.27.四川任务优化实践&#xff1a;执行效率提升50%以上 13.108.Spark 优化&#xff1a; 1.1.25.Spark优化与hive的区别 先理解spark与mapreduce的本质区别&#xff0c;算子之间&#xff08;…

【高性能计算】opencl语法及相关概念(四):结合opencv进行图像高斯模糊处理

目录 高斯模糊简介主函数&#xff1a;host端设备端函数&#xff1a;mywork.cl效果图对比 高斯模糊简介 高斯模糊是一种常用的图像处理技术&#xff0c;用于减少图像中的噪点和细节&#xff0c;并实现图像的平滑效果。它是基于高斯函数的卷积操作&#xff0c;通过对每个像素周围…

使用acme,自动续签免费的SSL,无忧http升级https

使用acme自动续签免费的SSL 安装acme.sh颁发域名将证书安装到nginx下配置nginx的ssl自动续签 这里只进行最简单的操作 安装acme.sh 进入你的用户目录&#xff0c;如果你使用root登陆&#xff0c;那么你的用户目录就是 /root/ curl https://get.acme.sh | sh -s emailmyexam…

Linux环境基础开发工具

xshellssh xshell--充当客户端&#xff0c;提供远程登录服务 yum 背景知识 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放…

Elasticsearch:利用矢量搜索进行音乐信息检索

作者&#xff1a;Alex Salgado 欢迎来到音乐信息检索的未来&#xff0c;机器学习、矢量数据库和音频数据分析融合在一起&#xff0c;带来令人兴奋的新可能性&#xff01; 如果你对音乐数据分析领域感兴趣&#xff0c;或者只是热衷于技术如何彻底改变音乐行业&#xff0c;那么本…

隧道结构健康监测系统,保障隧道稳定安全运行

隧道是地下隐蔽工程&#xff0c;会受到潜在、无法预知的地质因素影响&#xff0c;早期修建的隧道经常出现隧道拱顶开裂、地表沉降、隧道渗漏水、围岩变形、附近建筑物倾斜等隧道的健康问题变得日益突出&#xff0c;作为城市生命线不可或缺的一部分&#xff0c;为了确保隧道工程…

GraphQL渗透测试案例及防御办法

什么是GraphQL GraphQL 是一种 API 查询语言&#xff0c;旨在促进客户端和服务器之间的高效通信。它使用户能够准确指定他们在响应中所需的数据&#xff0c;从而有助于避免有时使用 REST API 看到的大型响应对象和多个调用。 GraphQL 服务定义了一个合约&#xff0c;客户端可…

计算机视觉与人工智能在医美人脸皮肤诊断方面的应用

一、人脸皮肤诊断方法 近年来&#xff0c;随着计算机技术和人工智能的不断发展&#xff0c;中医领域开始逐渐探索利用这些先进技术来辅助面诊和诊断。在皮肤望诊方面&#xff0c;也出现了一些现代研究&#xff0c;尝试通过图像分析技术和人工智能算法来客观化地获取皮肤相关的…

【工作笔记-0038】mongodb mongorestore 命令行导入 bson.gz数据

1. 导出的集合文件格式如下&#xff08;也就是导出的表文件&#xff09;&#xff1a; 例如&#xff1a; D:\Files\xxxx集合名称.bson.gz 怎样导出&#xff0c;这里不做介绍&#xff0c;用 mongodb compass 或者 studio 3t 都可以 2. 下载命令行导入工具&#xff1a; 官方…

ZLMeidaKit在Windows上启动时:计算机中丢失MSVCR110.dll,以及rtmp推流后无法转换为flv视频流解决

场景 ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放&#xff1a; ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放_zlm流媒体服务器_霸道流氓气质的博客-CSDN博客 按照以上教程启动MediaServer.exe时提示&am…