性能优化 | el-table中内嵌大量el-input控件导致渲染卡顿的问题

场景

项目中有一个应用场景,用户需要在表单中大量使用选择框以及输入框填写数据(每一行大概有三十几个输入框),当选择框与输入框达到一定数量的时候,页面会出现输入不连续、卡顿的现象,如下图:
需求原型.png

排查

查了一下网上的解决方案,大体是因为页面渲染过多的el-input输入框给浏览器带来较大的渲染压力导致的。基于这点,对项目作出优化。

引入虚拟列表

虚拟列表,简单来说就是页面并不渲染表格中的所有数据,只渲染可视窗口部分的数据,当用户拖动滚动条滚动的时候,逐渐加载数据。这个适用于表格中需要渲染大量数据的场景,从而减轻浏览器的渲染压力。

对于elementui中使用el-table加入虚拟列表,可以参考下面这篇文章:
element全网最简单el-table实现虚拟列表

参考上面的文章,做了一个初版的效果。但由于虚拟列表只渲染部分数据的特性,所以一定会带来一个缺陷,那就是会短暂出现白屏的问题,即用户看到未渲染的区域。排查原因得知是因为el-table的占位区域append设置为定高totalHeight

<!-- 占位 -->
<template #append><div :style="{ height: `${totalHeight}px` }"></div>
</template>...
totalHeight() {return this.tableData.length * this.itemHeight
}

经过思考,改成动态变化的高度,从而形成一种滚动触底更新的效果:

// 改变append的高度
updated() {if (this.$refs.multipleTable) {const bodyEl = this.$refs.multipleTable.$el.getElementsByTagName("tbody")[0]if (bodyEl.offsetHeight) {this.totalHeight = bodyEl.offsetHeight} else if (bodyEl.offsetHeight === 0 && this.tableData.length === 0) {this.totalHeight = 0}// 重新绘制表格this.$refs.multipleTable.doLayout()}
},

虚拟列表再优化

引入虚拟列表后,加载确实快不少,输入卡顿的显现也明显优化。但发现一个问题,原有的选择方法不生效,当用户滚动的时候,原有的选择项被清空。那么,如何记录选择列表的状态呢?elementui提供了一个reserve-selection的API,用于记录列表项的选择状态:
reserve-selection.png

当然,也需要重写@select="handleSelect"@select-all="handleSelectAll"方法:

// 监听选择全部
handleSelectAll() {if (this.isSelectAll) {this.tableData.forEach(item => {this.$refs.multipleTable.toggleRowSelection(item, false)})this.selectList = []this.isSelectAll = false} else {this.tableData.forEach(item => {this.$refs.multipleTable.toggleRowSelection(item, true)})this.selectList = this.tableDatathis.isSelectAll = true}
},
// 手动触发选择事件
handleSelect(selection) {this.selectList = selectionif (selection.length === this.tableData.length) {this.isSelectAll = true} else {this.isSelectAll = false}
},

引入虚拟输入框

引入虚拟列表后,效果确实提升了不少,至少在大数据量的情况下,不再会出现卡顿了(因为大数据量其实只渲染固定的数据)。但还有可以优化的空间吗?
我们之前提到,造成页面卡顿的原因,就是大量渲染了el-input以及el-select控件。那么,可以再进一步优化,以减少控件的渲染数量吗?我在这篇文章中找到了灵感:
vue大数据表格卡顿问题的完美解决方案
或者直接看文章提到的demo:
Demo
DEMO.png
核心思路就是,**只有当需要编辑的时候,才显示输入框,其余都显示内容。**这么一来,最多只会渲染1个编辑控件,卡顿问题可以进一步得到优化。

实现思路

  • template中根据条件选择渲染编辑控件,默认显示表格内容(同时通过修改样式模拟输入框必填标红);
  • 鼠标点击表格的时候,记录当前表格的坐标,用于切换编辑控件;
  • 页面根据渲染条件,切换编辑控件,同时自动聚焦到编辑框中。

示例代码如下所示:

<el-form-item :prop="'displayList.' + $index + '.出差地点'"><el-input v-if="focusCell === `${$index}-出差地点`" type="textarea" v-model="row['出差地点']" @blur="beforeComputedAll" autosize></el-input><div v-else :class="row['出差地点'] ? 'm-input' : 'custom-required'">{{ row['出差地点'] }}</div>
</el-form-item>

记录表格坐标可以使用el-table的@cell-click方法:

// 聚焦单元格
updateFocusCell(row, col, cell) {if (this.focusDebounce) {clearTimeout(this.focusDebounce)this.focusDebounce = null}this.focusDebounce = setTimeout(() => {const lineNo = row['行号']const prop = col.propertyconst idx = this.displayList.findIndex(item => item['行号'] === lineNo)if (this.focusCell !== `${idx}-${prop}`) {this.focusCell = `${idx}-${prop}`this.$nextTick(() => {target.focus()})}this.focusDebounce = null}, 20)
},

最终效果

最终效果.jpg

总结

至此,表格已经从一开始的输入卡顿,到现在基本是可以流畅输入了,使用体验得到大大的提升。当然还有优化的空间,比如校验逻辑的编写,以及一些相关的计算等等,那块就是属于算法层面的东西了,在此就不展开叙述。
对于表格大批量数据渲染的优化方案,总结如下:

  • 引入虚拟列表,只渲染可视化区域的数据;
  • 模拟编辑控件,仅在需要编辑的时候才展示;
  • 计算逻辑优化,减少计算时间。

第一次遇到这种类型的优化,觉得挺有意思的,在此做一个记录。如果大家有更好的优化方案也可以在评论区提出,欢迎大家一起学习~

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

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

相关文章

【信息系统项目管理师知识点速记】风险管理:规划风险管理

规划风险管理是确保项目风险得到有效管控的关键前期步骤,它为整个项目生命周期中识别、分析、应对和监控风险提供了蓝图。 核心目的 匹配度:确保风险管理策略与项目风险水平、组织及干系人重要性相匹配。适时调整:项目初期完成,但需在重大变动时重新评估和调整。输入要素 …

16.直方图均衡化

数字图像处理(17): 直方图均衡化处理 简介 直方图均衡化是一种简单有效的图像增强技术&#xff0c;通过改变图像的直方图来改变图像中各像素的灰度&#xff0c;主要用于增强动态范围偏小的图像的对比度。当原始图像的灰度分布较为集中的时候&#xff0c;可能造成图像不够清晰&…

如何高效率阅读文献

很多导师曾说&#xff0c;不应该花费超过30分钟阅读一篇论文&#xff0c;在某些特殊的时间段&#xff0c;30分钟甚至可能都算是太多的时间&#xff0c;比如&#xff1a;你正准备毕业论文或者想要发表论文的时候…… 文献阅读为何如此重要&#xff1f;又该如何有效快速的阅读&a…

C++基础与深度解析 | 什么是C++ | C++开发环境与相关工具 | C++编译/链接模型

文章目录 一、什么是C二、C的开发环境与相关工具三、C的编译/链接模型 一、什么是C C是一门比较流行的编程语言&#xff08;高级语言&#xff09;&#xff0c;同时也是一门复杂的语言。从TIOBE 编程社区指数中可以看出&#xff1a;在2024.04中&#xff0c;其编程语言受欢迎程度…

HCIP【BGP综合实验】

目录 一、实验拓扑图&#xff1a; 二、实验要求&#xff1a; 三、实验思路&#xff1a; 四、实验步骤&#xff1a; 1、进行网段的子网划分&#xff08;整个实验总共有19条网段&#xff09;&#xff1a; (1)首先&#xff0c;根据实验要求&#xff0c;将172.16.0.0/16全部划…

2024湖南理工学院程序设计竞赛(同步赛) G. 区间递减(思维题 分类讨论 ST表)

题目 https://ac.nowcoder.com/acm/contest/82672/G 思路来源 出题人 涼風青葉7代码 题解 注意到三种情况即可&#xff0c; 第一种情况&#xff0c;10 9 8 1 2&#xff0c;保留1 第二种情况&#xff0c;6 5 10 9 4 4&#xff0c;保留5 4 4 第三种情况&#xff0c;6 5 4&…

基于STM32单片机的二轮平衡小车

设计一个基于STM32单片机的二轮平衡小车是一个涉及硬件选择、软件编程、控制算法和机械设计的复杂项目。这里我可以给你一个大致的项目概述和一些基础的代码示例&#xff0c;但请注意&#xff0c;完整的项目设计和实现将需要更详细的规划和大量的调试工作。 1. 项目概述 二轮…

SpringBoot使用腾讯云实现短信功能

引入依赖 <!-- 腾讯云依赖 --> <dependency><groupId>com.tencentcloudapi</groupId><artifactId>tencentcloud-sdk-java</artifactId><version>3.1.270</version> </dependency>配置文件 # 腾讯云短信配置 sms:tence…

jdk8的新特征

1&#xff1a; jdk8中新增的方法 在jdk8中对接口进行了增强&#xff0c;在jdk8之前 interface 接口名{ 静态常量&#xff1a; 抽象方法&#xff1a; } 在jdk8之后 interface 接口名{ 静态常量&#xff1a; 抽象方法&#xff1a; 默认方法&#xff1a; 静态方法&#xff1a; } 2…

linux使用/etc/hosts.deny拒绝恶意ssh到本机

一、目标 在某些特殊情况下&#xff0c;服务器有很多恶意暴力ssh破解的攻击。解决的办法有很多&#xff0c;这里用/etc/hosts.deny增加黑名单的方式来简单阻止一下。 二、前言 /etc/hosts.allow 优先于 /etc/hosts.deny。 如果在allow和deny文件中都有某个ip&#xff0c;那…

JAVA基础--IO

IO 什么是IO 任何事物提到分类都必须有一个分类的标准&#xff0c;例如人&#xff0c;按照肤色可分为&#xff1a;黄的&#xff0c;白的&#xff0c;黑的&#xff1b;按照性别可分为&#xff1a;男&#xff0c;女&#xff0c;人妖。IO流的常见分类标准是按照*流动方向*和*操作…

人形机器人的组成原理、相关技术和行业应用

人形机器人的部件和工作原理 人形机器人的部件通常包括机身、关节、传感器、驱动器、控制器等。其工作原理是通过传感器收集环境信息&#xff0c;控制器根据预设的算法和程序生成动作指令&#xff0c;驱动器驱动关节运动&#xff0c;从而实现机器人的各种动作。 人形机器人主要…

Google与哈佛大学的科学家团队共同创造了一张人脑中一个极小部分的精细地图

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

插件:Best HTTP

一、简介 WebSocket WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在WebSocket API中&#xff0c;浏览器和服务器只需要完成一次握手&#xff0c;两者之间就直接可以创建持久性的连接&#xff0c;并进行双向数据传输。…

【SRC实战】无法支付的修改金额支付漏洞

挖个洞先 https://mp.weixin.qq.com/s/F4f8R4uKN0Q9BnTmjDMleg “ 以下漏洞均为实验靶场&#xff0c;如有雷同&#xff0c;纯属巧合 ” 01 — 漏洞证明 一、企业用户&#xff0c;标准商品 “ 支付订单需要公对公银行卡转账&#xff0c;如何绕过&#xff1f;” 1、点击任意…

bert 的MLM框架任务-梯度累积

参考&#xff1a;BEHRT/task/MLM.ipynb at ca0163faf5ec09e5b31b064b20085f6608c2b6d1 deepmedicine/BEHRT GitHub class BertConfig(Bert.modeling.BertConfig):def __init__(self, config):super(BertConfig, self).__init__(vocab_size_or_config_json_fileconfig.get(vo…

java入门-面向对象的三大特性

面向对象三大特性 封装 什么是封装 封装 是将代码及其处理的数据绑定在一起的一种编程机制&#xff0c;该机制保证了程序和数据都不受外部干扰且不被误用。 封装的作用 访问控制符 方法传参-值传递 传参类型是基本类型 程序案例&#xff1a; public static void main(St…

C++笔记(体系结构与内核分析)

1.OOP面向对象编程 vs. GP泛型编程 OOP将data和method放在一起&#xff0c;目的是通过封装、继承、多态提高软件的可维护性和可扩展性GP将data和method分开&#xff0c;可以将任何容器与任何算法结合使用&#xff0c;只要容器满足塞饭所需的迭代器类型 2.算法与仿函数的区别 …

Flutter 中的 Column 小部件:全面指南

Flutter 中的 Column 小部件&#xff1a;全面指南 在 Flutter 中&#xff0c;Column 是一个垂直布局的小部件&#xff0c;用于将子控件沿着垂直轴排列。Column 与 Row 相对&#xff0c;Row 是水平布局&#xff0c;而 Column 则是垂直布局。它非常适合用来创建列式布局&#xf…

AJAX前端与后端交互技术知识点以及案例

Promise promise对象用于表示一个异步操作的最终完成&#xff08;或失败&#xff09;及其结果值 好处&#xff1a; 逻辑更清晰了解axios函数内部运作机制成功和失败状态&#xff0c;可以关联对应处理程序能解决回调函数地狱问题 /*** 目标&#xff1a;使用Promise管理异步任…