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

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再次封装基础组件文档

相关文章:

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

一、此功能已集成到TTable组件中 二、最终效果 三、需求 某些页面不做分页时&#xff0c;当数据过多&#xff0c;会导致页面卡顿&#xff0c;甚至卡死 四、虚拟滚动 一、固定一个可视区域的大小并且其大小是不变的&#xff0c;那么要做到性能最大化就需要尽量少地渲染 DOM 元素…...

5.1 树和二叉树的定义

思维导图&#xff1a; 问题 为什么有树和二叉树&#xff1f; "树" 和 "二叉树" 都是数据结构中常用的结构&#xff0c;它们分别有其独特的应用和优点。我们可以从它们的定义和特性中理解为什么它们都存在。 1. **树 (Tree)&#xff1a;** - **定义**:…...

Java单元测试及常用语句 | 京东物流技术团队

1 前言 编写Java单元测试用例&#xff0c;即把一段复杂的代码拆解成一系列简单的单元测试用例&#xff0c;并且无需启动服务&#xff0c;在短时间内测试代码中的处理逻辑。写好Java单元测试用例&#xff0c;其实就是把“复杂问题简单化&#xff0c;建单问题深入化“。在编写的…...

详解Vue中的render: h => h(App)

声明:只是记录&#xff0c;会有错误&#xff0c;谨慎阅读 我们用脚手架初始化工程的时候&#xff0c;main.js的代码如下 import Vue from vue import App from ./App.vueVue.config.productionTip falsenew Vue({// 把app组件放入容器中render: h > h(App), }).$mount(#ap…...

归并排序的详解!

本文旨在讲解归并排序的实现&#xff08;递归及非递归&#xff09;搬好小板凳&#xff0c;干货来了&#xff01; 前序&#xff1a; 在介绍归并排序之前&#xff0c;需要给大家介绍的是什么是归并&#xff0c;归并操作&#xff0c;也叫归并算法&#xff0c;指的是将两个顺序序列…...

排盘程序算法探寻举例(陆先生八字)

算法实现&#xff1a; 1.庚生未月&#xff0c;燥土不能生金&#xff0c;日支申金为日主墙根&#xff0c;月干辛金比劫透出傍身&#xff0c;月干强。年干甲木自做寅木强根&#xff0c;又得月支乙木中气&#xff0c;甲木强旺有力&#xff0c;时干丙火七杀得未土余气&#xff0c;…...

考研408 | 【操作系统】终章

I/O设备的基本概念和分类 I/O设备&#xff1a; I/O设备的分类 1.按使用特性&#xff1a; 2.按传输速率分类&#xff1a; 3.按信息交换的单位分类&#xff1a; 总结&#xff1a; I/O控制器 I/O设备的机械部件&#xff1a; I/O设备的电子部件&#xff08;I/O控制器&#…...

亚马逊云科技生成式AI技术辅助教学领域,近实时智能应答2D数字人搭建

早在大语言模型如GPT-3.5等的兴起和被日渐广泛的采用之前&#xff0c;教育行业已经在AI辅助教学领域有过各种各样的尝试。在教育行业&#xff0c;人工智能技术的采用帮助教育行业更好地实现教学目标&#xff0c;提高教学质量、学习效率、学习体验、学习成果。例如&#xff0c;人…...

Programming abstractions in C阅读笔记:p139-p143

《Programming Abstractions In C》学习第55天&#xff0c;p139-p140&#xff0c;总结如下&#xff1a; 一、技术总结 1.文件I/O操作 文件I/O操作可以分为一下这些步骤&#xff1a; (1)声明文件指针对象。 File *infile;(2)打开文件 fopen()。打开文件的模式有“r”, “w…...

MyBatis-Plus学习笔记

1.MyBatis-Plus简介&#xff1a; MyBatis-Plus是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。MyBatis-Plus提供了通用的mapper和service&#xff0c;可以在不编写任何SQL语句的情况下&#xff0c;快速的实现对单…...

linux安装docker全过程

3. 第二步&#xff1a;设置docker的存储库。就两条命令&#xff0c;我们直接执行就好。 ​ sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo ​​ 4. 安装docker engine和docker-compose。 执行命…...

Spring 中存取 Bean 的相关注解

目录 一、五大类注解 1、五大类注解存储Bean对象 1.1Controller(控制器储存) 1.2Service(服务存储) 1.3Repository(仓库存储) 1.4Component(组件存储) 1.5Configuration(配置存储) 2、五大类注解小结 2.1为什么要这么多类注解 2.2 五大类注解之间的关系 二、方法注解 1.方法注…...

Camunda 7.x 系列【38】表单服务 FormService

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 2.7.9 本系列Camunda 版本 7.19.0 源码地址:https://gitee.com/pearl-organization/camunda-study-demo 文章目录 1. 概述2. 演示2.1 获取流程开始表单2.2 启动流程2.3 查询任务表单2.4 完成任务3. 实际开发…...

保姆级教程之SABO-VMD-SVM的西储大学轴承诊断

之前写过一篇优化核极限学习机的轴承诊断&#xff0c;今天再出一期基于SVM的轴承诊断。 依旧是包含了从数据处理&#xff0c;到减法优化器SABO算法优化VMD参数&#xff0c;再到支持向量机的故障诊断&#xff0c;实现故障诊断的全流程&#xff0c;其他类型的故障诊断均可参考此流…...

指向任意节点的带环链表

&#x1f308;图示指向任意节点的带环链表 如图&#xff1a; &#x1f308;快慢指针法判断链表是否带环 &#x1f31f;思路&#xff1a;快指针fast一次走2步&#xff0c;慢指针slow一次走1步&#xff0c;fast先进环在换中运动&#xff0c;随后slow进入环。两指针每同时移动…...

应用于伺服电机控制、 编码器仿真、 电动助力转向、发电机、 汽车运动检测与控制的旋变数字转换器MS5905P

MS5905P 是一款 12bit 分辨率的旋变数字转换器。 片上集成正弦波激励电路&#xff0c;正弦和余弦允许输入峰峰值 幅度为 2.3V 到 4.0V &#xff0c;可编程激励频率为 10kHz 、 12kHz 、 15kHz 、 20kHz 。 转换器可并行或串行输出角度 和速度对应的数字量。 MS5905…...

Ansible学习笔记(持续更新)

Ansible学习目录 1.自动化运维1.1 企业实际应用场景1.1.1 Dev开发环境1.1.2 测试环境1.1.3 发布环境1.1.4 生产环境1.1.5 灰度环境 1.2 程序发布1.3 自动化运维应用场景1.4 常用自动化运维工具 2.Ansible介绍和架构2.1 Ansible特性2.2 Ansible架构2.2.1 Ansible主要组成部分2.2…...

CCF HPC China2023|澎峰科技:使能先进计算,赋能行业应用

CCF HPC China2023圆满落幕&#xff01; 桂秋八月&#xff0c;为期三天的中国高性能计算领域最高规格盛会——2023CCF全球高性能计算学术年会&#xff08;HPC China&#xff09;在青岛红岛国际展览中心圆满落幕。行业超算大咖、顶级学界精英、先锋企业领袖参会者齐聚山东青岛&a…...

【FlowDroid】一、处理流程学习

FlowDroid 一、处理流程学习 下载配置源码概况代码逻辑分析analyzeAPKFilerunInfoflowprocessEntryPointcalculateCallbacks(sourcesAndSinks)再次回到processEntryPoint 自己做一些笔记 下载配置 参照我前面的文章可以使用FlowDroid安装初体验 为了看代码了解FlowDroid如何处…...

MyBatis——MyBatis插件原理

摘要 本博文主要介绍MyBatis插件机原理&#xff0c;帮助大家更好的理解和学习MyBatis。 一、插件机制概述 MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下&#xff0c;MyBatis允许使用插件来拦截的方法调用包括&#xff1a; Executor (update, que…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...

人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型

在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重&#xff0c;适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解&#xff0c;并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...

sshd代码修改banner

sshd服务连接之后会收到字符串&#xff1a; SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢&#xff1f; 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头&#xff0c…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...