13-Vue长列表优化 vue-virtual-scroller

news2024/11/16 0:31:12

回答:

在大型的企业级项目中经常要渲染大量的数据,这种长列表是一个很普遍的场景,当列表内容越来越多就会导致页面滑动卡顿白屏数据渲染较慢的问题;

这种情况主要发生在小程序、移动端或者后台管理的页面当中;

通常我们会采用分页的方式进行内容的逐渐获取,但是当内容越来越多时;

比如移动端的下拉刷新,不停的往上翻,到底部会加载更多内容,这样一来列表中会新增很多的元素,元素多了以后会触发浏览器的重排重绘,无论是内存的占用还是GPU的渲染都会带来很大的性能损耗,导致页面滑动卡顿数据渲染较慢的问题;

处理时要根据情况做不同处理:

  • 避免大数据量:采取分页的方式获取
  • 避免渲染大量数据:vue-virtual-scroller 插件等虚拟列表方案,只渲染视口范围内数据
  • 避免更新:使用 v-once 方式只渲染一次
  • 优化更新:通过 v-memo 缓存子树,有条件更新,提高复用,避免不必要更新
  • 按需加载数据:采用懒加载的方式,比如 tree 组件子树的懒加载

总之,还是要看具体需求,首先从设计上避免大数据获取和渲染;实在需要这样做可以采用虚拟列表的方式优化渲染数量;最后优化更新,如果不需要更新可以 v-once 避免更新,需要更新可以 v-memo 进一步优化大数据更新性能,其他可以采用的是交互方式优化,无限滚动,懒加载方案等。

页面卡顿的原因

根源:大量DOM元素的 reflow 和 repaint

修改是对当前DOM元素的修改,更新却是所有的DOM都更新

优化思路:

1、懒渲染
  • 懒加载,常见的长列表优化方案,常见于移动端
  • 原理:每次只渲染一部分,等渲染的数据即将滚动完时,再渲染下面部分
  • 优点:每次渲染一部分数据,速度快
  • 缺点:数据量大时,页面中依然存在大量DOM节点,占用内存过多,降低浏览器渲染性能,导致页面卡顿
  • 使用场景:数据量不大的情况下(比如1000条,具体还要看每条数据的复杂程度)
2、分页渲染

一般是后端给我们数据,我们只需把页码数,每页展示的数据量,给后端,后端给我们数据我们进行展示即可。

3、可视区域渲染

原理: 只渲染页面可视区域的列表项,非可视区域的数据 “完全不渲染”(预加载前面几项和后面几项) ,在滚动列表时动态更新列表项,为了防止白屏,所以实际会多加载几条数据

自己实现可视区渲染

父组件中

  • 使用 computed 缓存模拟一万条数据,
  • 通过属性绑定将 item (数据)、 size (每条数据的高度)和  showNumber (每次渲染的数据条数)传递给子组件

子组件中

  • 通过 props 接收父组件传递过来的属性;
  • 最外层盒子设置 overflow-y: scroll; 实现纵向滚动;
  • 最外层盒子固定高度 (最外层盒子高度 = size * showNumber);
  • 给外层盒子监听滚动事件,计算被卷起的数据高度;
  • 计算可视区数据的起始索引,start = 卷起的高度 /  单条数据高度;
  • 计算可视区数据的结束索引,end = 起始索引 + 可视区可展示的条数;
  • 取可视区域起始索引 start 和结束索引 end 的数据展示到可视区域;

父组件

模拟一万条数据

创建了一个拥有10000个元素的空数组,利用 fill() 函数初始化,所有的值都为空,再利用 map, 给数组返回 id 和 content,也就实现了数组赋值;

computed: {
	item () {
		return Array(10000).fill('').map((item, index) => ({
			id: index,
			content: `列表内容`+ index
		}))
	}
}

 子组件

ui结构

list 是可视区域

bar 是撑开盒子,使其能纵向滚动

  • 可视区容器:可以看作是在最底层,容纳所有元素的一个盒子。
  • 可滚动区域:可以看作是中间层,假设有 10000 条数据,每个列表项的高度是 50,那么可滚动的区域的高度就是 10000 * 50。这一层的元素是不可见的,目的是产生和真实列表一模一样的滚动条。
  • 可视区列表:可以看作是在最上层,展示当前处理后的数据,高度和可视区容器相同。可视区列表的位置是动态变化的,为了使其始终出现在可视区域。

理解以上概念之后,我们再看看当滚动条滚动时,我们需要做什么:

  1. 根据滚动距离和 item 高度,计算出当前需要展示的列表的 startIndex
  2. 根据 startIndex 和 可视区高度,计算出当前需要展示的列表的 endIndex
  3. 根据 startIndex 和 endIndex 截取相应的列表数据,赋值给可视区列表,并渲染在页面上
  4. 根据滚动距离和 item 高度,计算出可视区列表的偏移距离 startOffset,并设置在列表上

 

 接收父组件传递过来的数据  ,定义初始下标和结束下标

计算容器高度和被卷起的数据高度

给container监听滚动事件,起始下标就是卷去的数据条数,向下取整

结束下标就是 起始下标 + 要展示的数据条数

使用虚拟列表 vue-virtual-scroller 实现

对于长列表来说,我们大部分的操作都是:

1.懒加载,分页,

2.Object.freeze冻结数组取消响应式,因为大多时候都是展示

3.高清图替换成缩略图,因为很多时候长列表的图尺寸都比较小,所以可以用小图来代替

以上能解决大部分的长列表问题,在可以分页的情况下

当不能分页时,采用可视区渲染

items高度固定(RecycleScroller)

下载插件

yarn add vue-virtual-scroller --save

 在 main.js 注册

import "vue-virtual-scroller/dist/vue-virtual-scroller.css";
import VueVirtualScroller from "vue-virtual-scroller";

Vue.use(VueVirtualScroller);

 以下是必填项

Props

解释

默认值

items
可视区域要渲染的数据列表--
item-size
每项数据的高度null
style
可视区域的外层盒子高度--
v-slot = { item }
插槽,拿到每项数据item--

 以下按需要修改

Props

解释

默认值

prerender
告诉服务端(SSR)每次渲染几条数据0
buffer
可视区域外多渲染的数据高度,避免滚动留白200
keyField
用于标识项目和优化管理渲染视图的字段id

固定高度的作用域插槽参数

Slot

解释

默认值

item
每项数据--
index
每项数据的下标--
active
视图是否处于活动状态。活动视图被视为可见视图,并由RecycleScroller定位。非活动视图不被视为可见,并且对用户隐藏。如果视图处于非活动状态,则应跳过任何与渲染相关的计算。--

items高度固定(RecycleScroller),可上拉加载

Events

解释

默认值

resize
重新计算大小时触发--
visible
当滚动条认为自己在页面中可见时触发--
hidden
当滚动条隐藏在页面中时触发--
update (startIndex, endIndex)
每次更新视图时发出,仅当 :emitUpdate=“true”false

实现思路:

  • 添加 :emitUpdate="true" 和 @update 事件;
  • update函数传入两个形参,start 和 end ,判断当 end 等于数组列表的长度时,去请求接口来获取新的数据,然后加入到数组当中。

 items高度不固定(DynamicScroller),可上拉加载

Props(参数)

解释

默认值

item(必填)
每项数据--
active(必填)
保持视图,数据处于 active 状态,将防止不必要的大小重新计算。--
sizeDependencies
影响高度的值,如果发生变化,则重新计算--
watchData
深入监视更改以重新计算大小(不推荐,可能会影响性能)false
tag
组件要呈现的元素div
emitResize
每次重新计算大小时发出事件(可能会影响性能)false
minItemSize
列表项初次渲染使用的最小高度

Events(事件)

解释

默认值

resize
重新计算大小时触发,仅当 :emitUpdate=“true”false

小程序长列表优化实践 - 知乎

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

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

相关文章

K 个一组翻转链表——力扣25

题目描述 方法一&#xff09;模拟 class Solution{ public:pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail){ListNode* prev tail->next;ListNode* p head;while(prev!tail){ListNode* nex p->next;p->next prev;prev p;p nex; }r…

基于STM32+SHT30设计的环境温度与湿度检测系统(IIC模拟时序)

一、项目功能介绍 当前介绍基于STM32F103ZCT6芯片设计的环境温度与湿度检测系统设计过程。当前系统通过SHT30温湿度传感器采集环境温度和湿度数据&#xff0c;并通过模拟IIC时序协议将数据传输到STM32芯片上。然后&#xff0c;STM32芯片通过处理这些数据并将它们显示在0.91寸O…

微信小程序和微信公众号之前的关系

微信小程序和公众号是相互独立的&#xff0c;是2个不同的东西 在公众号上关联小程序后&#xff0c;可以在公众号的底部菜单栏点击直接进入小程序。2者的用户可以互通&#xff0c;其他就没别的

【C++】STL——string类对象的修改操作、string类对象修改函数的介绍和使用、push_back、append、operator+

文章目录 1.string类对象的修改操作&#xff08;1&#xff09;push_back&#xff08;尾插单个字符&#xff09;&#xff08;2&#xff09;append&#xff08;尾插字符串&#xff09;&#xff08;3&#xff09;operator&#xff08;尾插字符串str&#xff09;&#xff08;4&…

linux基础 - SHELL1

目录 一、基础 1.test测试语句 2.逻辑运算 3.类型判断 4.数值判断 5.字符串比较 6.计算表达式 二、shell数组 1.单行定义 2.多行定义 3.单元素定义 4.查看元素 5.基于内容找索引 6.增删改 三、shell高级 1.重定向 2.其他符号 3.信息符号 4.if语句 5.else …

unity --- DoTween插件安装与使用

目录 一.简介 1.1 插件下载 1.2 官方文档 二.导入和设置 三.示例代码 1 循环动画&#xff1a;SetLoops(-1 , loopType ) 2. 动画循环次数&#xff1a;SetLoops( count ) 3. 动画事件监听与回调&#xff1a;OnStart \ OnComplete 4. 动画延迟回调&#xff1a;SetDelay …

Java8特性:函数式接口与Stream流

1、 函数式接口 &#xff08;1&#xff09;四大函数式接口 &#xff08;2&#xff09;代码01 //void accept(T t);消费型接口&#xff0c;有参数&#xff0c;无返回 Consumer<String> consumer t->{System.out.println(t); }; consumer.accept("a"); //…

DAY42:动态规划(二)斐波那契数列+爬楼梯+最小花费爬楼梯

文章目录 509.斐波那契数列思路&#xff1a;动规五步确定dp数组和数组下标含义递推公式DP数组初始化遍历顺序打印DP数组 完整版debug测试 空间复杂度优化版优化思路 70.爬楼梯思路DP数组的含义以及下标含义递推公式DP数组初始化遍历顺序打印DP数组 完整版debug测试 空间复杂度优…

10.24UEC++、事件

1. 类内部声明事件类型&#xff1a; 生成actor 绑定到事件上 实现&#xff1a; 移除&#xff1a;

使用docker安装redis并使用redis deskTop manager连接

使用docker安装redis 提前准备环境 linux、 docker环境 # 使用命令查看docker环境是否正常docker images(任何一个docker命令就可以&#xff0c;不一定必须这个) 下载redis镜像 # 使用命令下载镜像文件docker pull redis 确认镜像 # 使用命令查看镜像docker images使用redis d…

功能测试的测试流程是什么样的?

概述 本流程是描述软件功能自动化测试过程中的步骤、内容与方法&#xff0c;明确各阶段的职责、活动与产出物。 流程活动图 活动说明 测试计划&#xff08;可选&#xff09; 与以前的测试计划过程一致&#xff0c;只是在原来的测试计划中&#xff0c;添加对项目实施自动化测试…

Qt窗体全屏与复原,子窗体全屏与复原

QT QWidget窗体全屏时&#xff0c;全屏与最大化的区别时最大化有标题框全屏没有框&#xff0c;可以使用自带的函数&#xff1a; showFullScreen(); 复原时也有专门的函数&#xff1a; showNormal(); 如果我想在点击最大化按钮时&#xff0c;让窗体全屏。这个时候最好有线程…

学好工作汇报,你离升职加薪也就不远了

在职场中&#xff0c;工作汇报是展示你的价值和成果的重要环节。无论你是想要升职还是加薪&#xff0c;一个出色的工作汇报能够给你带来巨大的竞争优势。然而&#xff0c;许多人对于如何进行有效的工作汇报感到困惑。在本文中&#xff0c;我们将向您介绍一些关键技巧和策略&…

路径规划算法:基于骑手优化优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于骑手优化优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于骑手优化优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化…

Linux学习之vim在光标所在处写入内容,保存退出

vim insertTest使用vim打开一个叫做insertTest新文件。 输入命令之后&#xff0c;按下Enter&#xff08;回车键&#xff09;&#xff0c;就可以进入下边的操作页面。 按i在当前光标位置处&#xff0c;就可以插入内容了。 接下来写入内容跟记事本里边是差不多的。 按一下…

【Spring】Spring基础知识 Java开发必看

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前专攻C/C、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL、蓝桥杯&am…

vue拼接html中onclick的触发方式,模版字符串拼接点击事件在vue项目中不生效问题

模版字符串拼接点击事件在vue项目中不生效问题 下面的点击事件没有任何效果&#xff0c;但是如果换成onclick绑定事件则会提示没有该方法。主要原因是&#xff1a; 模版字符串中拼接的html片段中的方法调不到vue中this.methods里的东西&#xff0c;因为methods里的代码是编译…

物体识别(香蕉)

✨✨✨ 感谢优秀的你打开了小白的文章 “希望在看文章的你今天又进步了一点点&#xff0c;生活更加美好&#xff01;”&#x1f308;&#x1f308;&#x1f308; 目录 1.数据集下载 2.数据集导入 3.结果 1.数据集下载 包含所有图像和CSV标签文件的香蕉检测数据集可以直接从互…

day1-二分查找

二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target 9 输出: 4 解…

单片机基于stm32单片机的数字温度计设计_kaic

摘 要 古往今来,陶瓷在我们的生活中一直都是不可或缺的物品,而随着当今社会经济的快速发展,人们对于这些高档陶瓷产品的使用性能和产品质量上的要求也愈加严格。那么在陶瓷品的生产过程中,想要提高陶瓷品的品质和合格率,能够随时监测温度的温度计是必不可少的。 本课题的研究是…