前端性能优化 - 虚拟滚动

news2024/11/22 14:54:56

一 需求背景

需求:在一个表格里面一次性渲染全部数据,不采用分页形式,每行数据都有Echart图插入。
问题:图表渲染卡顿
技术栈:Element UI
卡顿原因:页面渲染时大量的元素参与到了重排的动作中,性能差
解决办法:虚拟滚动

二 虚拟滚动原理

虚拟滚动其实就是综合数据分页和无限滚动的方法,在有限的视口中只渲染我们所能看到的数据,超出视口之外的数据就不进行渲染,可以通过计算可视范围内的单元格,保证每一次滚动渲染的DOM元素都是可以控制的,不会担心像数据分页一样一次性渲染过多,也不会发生像无限滚动方案那样会存在数据堆积,是一种很好的解决办法。

假设实际开发中服务端一次响应20万条列表数据,此时设备屏幕只允许容纳20条,那么用户理论上只可以看见20条数据,其他的数据不会进行渲染加载。如果前端将20万条数据全部渲染成DOM元素,可能造成程序卡顿,占用较大资源,非常影响用户体验,那么虚拟滚动技术就完美的解决了这一问题。

在这里插入图片描述

可以计算:卷入行数 = scrollTop(卷入高度) / 每行的高度(itemH)

如何计算可视区域渲染的元素以及实现虚拟滚动,步骤如下:

  • 统一设置每一行的高度需要相同,方便计算。
  • 需要计算渲染数据数量(数组的长度),根据每行的高度以及元素的总量计算整个DOM渲染容器的高度。
  • 获取可视区域的高度
  • 触发滚动事件后,计算偏移量(滚动条据顶距离),再根据可视区域高度计算本次偏移的截止量,得到需要渲染的具体数据。
  • 对于与表格的列来说,需要做虚拟滚动的话,在x轴同样可以根据以上步骤执行,实现横向虚拟滚动。

三 项目具体代码:

  <el-table
     ref="latestPositionRef"
     v-loading="tableLoading"
     class="table-fixed"
     size="mini"
     :data="sliceTable"
     height="355px"
     :cell-style="cellStyle"
     row-key="secId"
     @sort-change="handleSortChange"
     @selection-change="handleSelectionChange"
   >
     <el-table-column type="selection" width="55" align="center" :reserve-selection="true" />
     <el-table-column label="排名" width="50px" align="center" fixed>
       <template slot-scope="scope">{{ scope.$index + 1 }}</template>
     </el-table-column>
     <DynamicColumn
       v-for="(ite, index) in overviewColumns"
       :key="index"
       :item="ite"
       :empty="1"
       :data-list="infoList"
       table-sign="latest-position-list"
       :schemas="overviewColumns"
       @changeColumn="(cols)=>{overviewColumns=cols;}"
     />
     <el-table-column label="备注设置" align="center" width="50" fixed="right">
       <template slot-scope="scope">
         <el-button
           v-if="scope.row.secId"
           type="text"
           size="mini"
           plain
           @click="setRemark(scope.row)"
         >查看</el-button>
       </template>
     </el-table-column>
   </el-table>
data() {
	return {
	  // 动态列-ETF精选
      overviewColumns: this.$columns.getColumns('etf_selected_list'),
      // 表格数据
      infoList: [],
      showInfoList: [],
      
	  // 开始索引
      startIndex: 0,
      // 空元素,用于撑开table的高度
      vEle: undefined,
      // 每一行高度
      itemHeight: 42,
 	}
}
watch: {
    sliceTable: {
      handler() {
      // 解决表格错位问题
        this.$nextTick(() => {
          this.$refs.latestPositionRef.doLayout()
        })
      },
      deep: true
    },
}
  async created() {
    // 创建一个空元素,这个空元素用来撑开 table 的高度,模拟所有数据的高度
    this.vEle = document.createElement('div')
  },
  computed: {
    // 这个是截取表格中的部分数据,放到了 table 组件中来显示
    sliceTable() {
      return this.showInfoList.slice(this.startIndex, this.startIndex + 6)
    },
  }
 /** 加载ETF精选列表数据 */
   loadData() {
     console.log('loadData')
     const start_i = this.showInfoList.length
     for (let i = start_i; i < start_i + 10; i++) {
       this.showInfoList.push(this.infoList[i])
     }
     this.$nextTick(() => {
       // 设置成绝对定位,这个元素需要我们去控制滚动
       this.$refs.latestPositionRef.$el.querySelector(
         '.el-table__body'
       ).style.position = 'absolute'
       // 计算表格所有数据所占内容的高度
       this.vEle.style.height =
         this.showInfoList.length * this.itemHeight + 'px'
       // 把这个节点加到表格中去,用它来撑开表格的高度
       this.$refs.latestPositionRef.$el
         .querySelector('.el-table__body-wrapper')
         .appendChild(this.vEle)
       // 重新设置曾经被选中的数据
       this.selection.forEach((row) => {
         this.$refs.latestPositionRef.toggleRowSelection(row, true)
       })
     })
   },

   tableScroll() {
     console.log('tableScroll')
     const bodyWrapperEle = this.$refs.latestPositionRef.$el.querySelector(
       '.el-table__body-wrapper'
     )
     console.log(bodyWrapperEle, 'bodyWrapperEle')
     // 滚动的高度
     const scrollTop = bodyWrapperEle.scrollTop
     // 下一次开始的索引
     this.startIndex = Math.floor(scrollTop / this.itemHeight)
     // 滚动操作
     bodyWrapperEle.querySelector(
       '.el-table__body'
     ).style.transform = `translateY(${this.startIndex * this.itemHeight}px)`
     // 滚动操作后,上面的一些 tr 没有了,所以需要重新设置曾经被选中的数据
     this.selection.forEach((row) => {
       this.$refs.latestPositionRef.toggleRowSelection(row, true)
     })

     // 滚动到底,加载新数据
     if (
       bodyWrapperEle.scrollHeight <=
       scrollTop + bodyWrapperEle.clientHeight
     ) {
       if (this.showInfoList.length === this.infoList.length) {
         this.$message.warning('没有更多了')
         return
       }
       this.loadData()
       // 解决el-table中内容错位
       // this.$nextTick(() => {
       //   this.$refs.latestPositionRef.doLayout()
       // })
     }
   }

四 其他方案:

分段渲染、数据分页、无限滚动

学习:https://www.modb.pro/db/122781

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

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

相关文章

2023 uniapp( vue3)使用canvas生成海报并保存,taro/微信小程序也适用

有段时间没写vue了&#xff0c;有点生疏了...... 1、代码有注释&#xff0c;完整代码如下 <template><view class"page"><canvas class"canvas" v-if"isShow" :style"{width:${canvasWidth}px,height:${canvasHeight}px}&…

格式化之 %d,%2d, %02d

在Java中&#xff0c;%d&#xff0c;%2d 和 %02d 都用于格式化整数&#xff1a; %d&#xff1a; %d 是格式化整数的基本占位符。当使用 %d 格式化整数时&#xff0c;它将使用默认的对齐方式&#xff0c;通常是右对齐&#xff0c;并没有指定宽度。例如&#xff0c;System.out.…

解决 webpack 4.X:autoprefixer 插件使用不起作用的两种解决方案

1、问题描述&#xff1a; 其一、存在的问题为&#xff1a; 加载 autoprefixer 插件的过程中&#xff0c;页面却显示并没有自动添加浏览器的厂商前缀; 其二、问题描述为&#xff1a; 在写 CSS3 这些新的特性时&#xff0c;存在着不同的浏览器解析这些新特性时&#xff0c;需…

学习package.json

package.json 文件&#xff0c;它是项目的配置文件&#xff0c;常见的配置有配置项目启动、打包命令&#xff0c;声明依赖包等。package.json 文件是一个 JSON 对象&#xff0c;该对象的每一个成员就是当前项目的一项设置。 {"name": "monorepo_frame",&q…

FTP服务器操作手册

FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机&#xff0c;它们依照FTP协议提供服务。FTP协议是File Transfer Protocol(文件传输协议)&#xff0c;专门用来传输文件的协议。FTP服务器是企业里经常用到的服务器&#xff0c;今天就介绍一…

RGB与YUV公式转换推导

目录 简介 Full Range公式推导 Limit Range推导 验证测试 参考资料 简介 RGB与YUV之间的转换有很多种标准&#xff0c;不同标准系数不一样&#xff0c;而且经常容易搞混淆&#xff0c;另外还有full range和limitrange的不同。其实这些转换系数都是推导出来的&#xff0c;…

【通览一百个大模型】Baize(UCSD)

【通览一百个大模型】Baize&#xff08;UCSD&#xff09; 作者&#xff1a;王嘉宁&#xff0c;本文章内容为原创&#xff0c;仓库链接&#xff1a;https://github.com/wjn1996/LLMs-NLP-Algo 订阅专栏【大模型&NLP&算法】可获得博主多年积累的全部NLP、大模型和算法干货…

【数据结构与算法】two X 树的遍历以及功能实现

前言&#xff1a; 前面我们已经提到过树、二叉树的概念及结构、堆排序、Top-k问题等的知识点&#xff0c;这篇文章我们来详解一下二叉树的链式结构等问题。 &#x1f4a5;&#x1f388;个人主页:​​​​​​Dream_Chaser&#xff5e; &#x1f388;&#x1f4a5; ✨✨专栏:htt…

JVM工具使用(jstat + jmap)

命令格式 jstat -gcutil pid interval(ms) 举例&#xff1a; jstat -gcutil 16361 1000 线上服务器的GC情况如下&#xff1a; 参数说明如下&#xff1a; S0: 新生代中Survivor space 0区已使用空间的百分比S1: 新生代中Survivor space 1区已使用空间的百分比E: 新生代已使用空…

ETL实现实时文件监听

一、实时文件监听的作用及应用场景 实时文件监听是一种监测指定目录下的文件变化的技术&#xff0c;当产生新文件或者文件被修改时&#xff0c;可实时提醒用户并进行相应处理。这种技术广泛应用于数据备份、日志管理、文件同步和版本控制等场景&#xff0c;它可以帮助用户及时…

Nacos 下载运行及配置

Nacos 服务注册与配置中心&#xff0c;兼顾两者 文章目录 Nacos 服务注册与配置中心&#xff0c;兼顾两者一、简介二、相关文档2.1 Nacos官网2.2 官方文档 三、下载并运行Nacos3.1 下载压缩包3.2 解压缩3.3 运行命令3.4 访问Nacos控制台 附录&#xff1a;各种注册中心比较 Naco…

CAS是“Compare and Swap“(比较并交换)

CAS是"Compare and Swap"&#xff08;比较并交换&#xff09; 一&#xff0c;介绍 CAS是"Compare and Swap"&#xff08;比较并交换&#xff09;的缩写&#xff0c;是一种多线程同步的原子操作。它基于硬件的原子性保证&#xff0c;用于解决并发环境下的…

在前台页面中console怎么查vue.prototype

在测试项目接口时发现调用接口调用异常&#xff0c;怀疑可能是网省配置问题 1. 打开前台页面。 2. 右键点击页面&#xff0c;选择"检查元素"或者"审查元素"。 3. 在打开的开发者工具中&#xff0c;选择"控制台"选项卡。 4. 在控制台中输入以下代…

TCP通信实战案例-即时通信

即时通信是什么含义&#xff0c;要实现怎么样的设计&#xff1f; 即时通信&#xff0c;是指一个客户端的消息发出去&#xff0c;其他客户端可以接收到。 即时通信需要进行端口转发的设计思想。 服务端需要把在线的Socket管道存储起来。 一旦收到一个消息要推送给其他管道。…

05-01 jdk,tomcat,mariadb数据库和profile多环境

1.卸载系统默认安装jdk # java -version # rpm -qa|grep openjdk -i # rpm - e --nodeps 需要删除的软件2.安装jdk 2.1新建jdk安装目录并解压 # mkdir /usr/java # cd /usr/ # tar -zxvf jdk-8u191-linux-x64.tar.gz # mv jdk-8u191/ /usr/java/2.2配置环境变量 # vim /etc/…

【Javascript】等于与全等于

var a1;if(a1){console.log(你好&#xff01;&#xff01;);} 如果a赋值为 1 的时候 var a1;if(a1){console.log(你好&#xff01;&#xff01;);}仍然会执行 console.log(你好&#xff01;&#xff01;); 所以在开发中如果if语句里要使用等于的时候使用 var a1;if(a1)…

编程小白的自学笔记十七(python办公自动化操作EXCEL表格之作图)

系列文章目录 编程小白的自学笔记十六&#xff08;python办公自动化操作EXCEL表格&#xff09; 编程小白的自学笔记十五&#xff08;python办公自动化操作EXCEL表格&#xff09; 编程小白的自学笔记十四&#xff08;python办公自动化创建、复制、移动文件和文件夹 编程小白…

Qt 项目实战 | 多界面编辑器

Qt 项目实战 | 多界面编辑器 Qt 项目实战 | 多界面编辑器界面设计创建子窗口类 官方博客&#xff1a;https://www.yafeilinux.com/ Qt开源社区&#xff1a;https://www.qter.org/ 参考书&#xff1a;《Qt 及 Qt Quick 开发实战精解》 Qt 项目实战 | 多界面编辑器 开发环境&…

运行segment anything模型的web demo 教程

这个web应用放在在源码的demo文件夹里&#xff1a; 这个前端仅基于React的web演示了如何加载固定图像和相应的SAM image embedding的.npy文件。 运行需要配置npm环境。 首先导出onnx的模型&#xff1a; import torch import numpy as np import cv2 import matplotlib.pyplo…

解决 Vue3 + Element Plus 树形表格全选多选以及子节点勾选的问题

原文链接&#xff1a; 解决 Vue3 Element Plus 树形表格全选多选以及子节点勾选的问题 前言 最近用到了 Element Plus 组件库的中的树形表格&#xff0c;但官网例子只能做到一层勾选&#xff0c;不能做到多层勾选&#xff0c;无法满足业务需求&#xff0c;所以研究了下&#…