vue - 常见的性能优化
文章目录
- vue使用中常见的性能优化
- 1, v-for 遍历避免同时使用 v-if
- 2, 如果需要使用v-for给每项元素绑定事件时 可以使用事件代理**
- 3, 一些数据不做响应式
- 4,一些页面采用`keep-alive`缓存组件
- 5,第三方UI库按需导入
- 6,列表数据的懒加载 上滑加载分页数据
- 7,变量本地化
- 8,事件的销毁
vue使用中常见的性能优化
1, v-for 遍历避免同时使用 v-if
在 Vue2 中 v-for
优先级更高,所以编译过程中会把列表元素全部遍历生成虚拟 DOM,再来通过 v-if 判断符合条件的才渲染,就会有多余的逻辑判断和造成性能的浪费,因为我们希望的是不符合条件的虚拟 DOM都不要生成;
1,为了过滤一个列表中的项目 (比如 v-for="user in users" v-if="user.isActive"
)。在这种情形下,可以将 users 替换为一个计算属性或者方法 (比如 activeUsers),让其返回过滤后的列表;
<ul><liv-for="user in activeUsers":key="user.id">{{ user.name }}</li>
</ul>methods:{// 方法activeUsers(){//在这里面处理需要显示的数据 然后返回筛选过的列表}
}
2,为了避免渲染本应该被隐藏的列表 (比如 v-for="user in users" v-if="shouldShowUsers"
)。这种情形下,请将 v-if 移动至容器元素上 (比如 ul、ol)。
<ul v-if="shouldShowUsers"><liv-for="user in users":key="user.id">{{ user.name }}</li>
</ul>
在 Vue3 中 v-if
的优先级更高,就意味着当判断条件是 v-for 遍历的列表中的属性的话,v-if 是拿不到的;
注意
:永远不要把 v-if 和 v-for 同时用在同一个元素上。
2, 如果需要使用v-for给每项元素绑定事件时 可以使用事件代理**
事件代理的本质就是利用事件冒泡到父元素的特性。这样就可以不用在循环的节点上每一个都加事件了;如下:
在父元素ul上面添加点击事件,如过需要传参的话 只需要添加自定义属性即可,比如下面的 id属性
<!-- 使用事件委托进行处理和传参 添加自定义属性id --><ul class="weekdays" @click="debounce($event)"><li v-for="(item, index) in dayList" :key="index" :id="index" >{{ item.day }}</li></ul>
// 事件委托处理debounce(event) {if (event.target && event.target.nodeName == "LI") {// 现在就可以拿到当前的节点 所以就能拿到里面的属性和数据console.log("我点击的是:", event.target);}},
事件代理好处有2 个
1,将事件处理程序代理到父节点,减少内存占用率;
2,动态生成子节点时能自动绑定事件处理程序到父节点;
3, 一些数据不做响应式
一些数据不做响应式 比如会员列表、商品列表之类的,只是纯粹的数据展示,不会有任何动态改变的场景下,就不需要对数据做响应化处理,可以大大提升渲染速度;
可以使用 Object.freeze()
方法冻结一个对象,该方法冻结的对象不能被修改;即不能向这个对象添加新属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值,以及该对象的原型也不能被修改;
export default {data: () => ({userList: []}),async created() {const users = await axios.get("/api/users");this.userList = Object.freeze(users);}
};
Vue2 的响应式源码地址:src/core/observer/index.js - 144行
是这样的:
export function defineReactive (...){// getOwnPropertyDescriptor 返回指定对象上一个自有属性对应的属性描述符// 也就是直接赋予该对象的属性,不需要从原型链上进行查找的属性const property = Object.getOwnPropertyDescriptor(obj, key)判断configurable` 为 `false`不做处理if (property && property.configurable === false) {return}...
}
可以看到一开始就判断 configurable
为 false
的直接返回不做响应式处理;
configurable` 为 `false` 表示这个属性是不能被修改的,而冻结的对象的 `configurable` 就是为 `false
这是vue正常定义在data里面的数据,会自动把下面的所有属性都添加get和set属性,有多少就添加多少:
开始冻结对象
:
freList是请求后端的列表数据;
created() {this.dayList = Object.freeze(freList)console.log("daylist:",this.dayList);},
可以看出已经没有get和set属性了,但同时这些数据也不具备响应式了;
4,一些页面采用keep-alive
缓存组件
比如在表单输入页面进入下一步后,再返回上一步到表单页时要保留表单输入的内容、比如在列表页>详情页>列表页
,这样来回跳转的场景等;
基础使用:
如果需要缓存整个项目,则如下设置(直接包裹根router-view即可):<keep-alive><router-view> </router-view></keep-alive>缓存部分页面或者组件,使用route.meta属性<keep-alive><router-view v-if="$route.meta.keepAlive"></router-view></keep-alive><router-view v-if="!$route.meta.keepAlive"></router-view>注:<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。<keep-alive><component :is="view"></component></keep-alive>
注意: 配置了keepAlive的页面,在再次进入时不会重新渲染(第一次进来时会触发所有钩子函数),该页面内的组件同理不会再次渲染。
而这可能会导致该组件内的相关操作(那些每次都需要重新渲染页面的操作:如父子组件间的传值)不再生效。 这一点可能会导致一些莫名其妙而又无从查证的bug;
vue2.1.0 新增了include,exclude俩个属性,允许组件有条件的缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示。
<!-- 逗号分隔字符串 --><keep-alive include="a,b"><component :is="view"></component></keep-alive><!-- 正则表达式 (需要 `v-bind`绑定) --><keep-alive :include="/a|b/"><component :is="view"></component></keep-alive><!-- 数组 (需要 `v-bind`绑定) --><keep-alive :include="['a', 'b']"><component :is="view"></component></keep-alive>
注:匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。
动态判断,使用v-bind:include
<keep-alive :include="includedComponents"><router-view></router-view>
</keep-alive>includedComponents动态设置即可
使用beforeRouteLeave或者afterEach中进行拦截处理
如在项目在Category组件中的设置:
beforeRouteLeave(to,from,next){if(to.name=='DemoIndex'){if(!from.meta.keepAlive){from.meta.keepAlive=true}next()}else{from.meta.keepAlive=falseto.meta.keepAlive=falsenext()}
},
在beforeRouteLeave中to.name根据具体的路由进行动态缓存设置
使用keepAlive后生命周期变化(重要):
首次进入缓存页面:beforeRouteEnter --> created --> mounted --> activated --> deactivated
再次进入缓存页面:beforeRouteEnter --> activated --> deactivated
注:
1、这里的activated非常有用,因为页面被缓存时,created,mounted等生命周期均失效,你若想进行一些操作,那么可以在activated内完成(下面会举个栗子:列表页回到上次浏览位置)
2、activated keep-alive组件激活时调用,该钩子在服务器端渲染期间不被调用。
3、deactivated keep-alive组件停用时调用,该钩子在服务端渲染期间不被调用。
5,第三方UI库按需导入
比如 vantUi, element-ui库的按需引入;见这篇文章
6,列表数据的懒加载 上滑加载分页数据
列表数据的懒加载滚动条上划到底时开始请求下一页的数据,尽量配合防抖函数使用,防止一瞬间请求的次数太多。
如下代码
:
这边我用的是vue3写的,vue2只是获取节点的方式不一样,其他都一样的;
onMounted(() => {// 获取滚动容器的节点let containerEle = showContentEl.value;if (!containerEle) return;// 监听滚动条containerEle.addEventListener("scroll", function () {const clientHeight = containerEle.clientHeight;const scrollTop = parseInt(containerEle.scrollTop);const scrollHeight = containerEle.scrollHeight;// 判断是否滚动条是否滚动到底 (-1是为了控制误差)if (clientHeight + scrollTop >= scrollHeight - 1) {// 开始防抖请求数据debounceLoadMaterialList();}});
});<template><div class="container"><div class="list">展示的列表数据</div></div>
</template>
设置接口防抖:
import * as _ from "lodash";
// 设置接口防抖
const debounceLoadMaterialList = _.debounce(loadMaterialList, 500);
7,变量本地化
简单说就是把会多次引用的变量保存起来,因为每次访问 this.xx
的时候,由于是响应式对象,所以每次都会触发 getter
,然后执行依赖收集的相关代码,如果使用变量次数越多,性能自然就越差;
从需求上说在一个函数里一个变量执行一次依赖收集就够了,可是很多人习惯性的在项目中大量写 this.xx
,而忽略了 this.xx
背后做的事,就会导致性能问题了;
比如下面vue2的例子
:
<template><div :style="{ opacity: number / 100 }"> {{ result }}</div>
</template>
<script>
import { someThing } from '@/utils'
export default {props: ['number'],computed: {base () { return 100 },result () {let base = this.base, number = this.number // 保存起来 -- 变量本地化for (let i = 0; i < 1000; i++) {number += someThing(base) // 避免频繁引用 this.xx}return number}}
}
</script>
8,事件的销毁
Vue 组件销毁时,会自动解绑它的全部指令及事件监听器,但是仅限于组件本身的事件;
而对于定时器
、 addEventListener
注册的监听器等,就需要在组件销毁的生命周期钩子中手动销毁或解绑,以避免内存泄露;
<script>
export default {created() {this.timer = setInterval(this.refresh, 2000)addEventListener('touchmove', this.touchmove, false)},beforeDestroy() {clearInterval(this.timer)this.timer = nullremoveEventListener('touchmove', this.touchmove, false)}
}
</script>
相关文章:

vue - 常见的性能优化
文章目录 vue使用中常见的性能优化1, v-for 遍历避免同时使用 v-if2, 如果需要使用v-for给每项元素绑定事件时 可以使用事件代理**3, 一些数据不做响应式4,一些页面采用keep-alive缓存组件5,第三方UI库按需导入6&#…...
微服务系列文章 之 Nginx服务状态监控的方法
在Nginx的插件模块中有一个模块stub_status可以监控Nginx的一些状态信息,默认安装可能没有这个模块,手动编译的时候加一下即可。 1. 模块安装 先使用命令查看是否已经安装这个模块: [rootihxb123Z nginx]# ./nginx -V (V大写会显示版本号和…...

【网络系统集成】路由器实验
1.实验名称:路由器RIP协议配置 2.实验目的 在PacketTracer中进行模拟实验,配置RIP协议,验证RIP协议更新时间及路由状态变化,加深对路由器RIP协议相关知识的理解与掌握。 3.实验内容 (1)拓扑结构图 (2)ip地址分配与端口分配...
【mac 安装Miniconda】
1.下载Miniconda 注意mac是什么版本,m1下载m1版本 https://docs.conda.io/en/latest/miniconda.html#macos-installers 2.安装Miniconda 在下载文件所在目录下打开终端,输入一下命令: bash Miniconda3-latest-MacOSX-x86_64.sh 一路回车&…...

螺栓疲劳计算-风电行业,参考GL2010, ST0361,1993-1-9
由于不想再重新排版了,于是转成了图片。...
QT学习之旅 - QThread多线程
文章目录 首先是主线程 其次是一个程序 通过一个QThread来放入程序 进阶一点: 手动开启关闭线程俩个线程 其实QT中的thread(线程)是很容易的 首先是主线程 #include "mainwindow.h" #include "ui_mainwindow.h"#include <QDebug>MainWindow::MainWin…...

PROFINET转TCP/IP网关TCP/IP协议的含义是
大家好,今天要和大家分享一款自主研发的通讯网关,远创智控YC-PN-TCPIP。这款网关可是集多种功能于一身,PROFINET从站功能,让它在通讯领域独领风骚。想知道这款网关如何实现PROFINET和TCP/IP网络的连接吗?一起来看看吧&…...

计算机网络基础第六章
一、应用层概述 1.1 网络应用模型 1.1.1 客户/服务器(C/S)模型 1.1.2 P2P模型 二、域名解析系统——DNS系统 2.1 域名 2.2 域名服务器 2.3 域名解析过程 三、文件传输协议——FTP 3.1 FTP服务器和用户端 3.2 FTP工作原理 四、电子邮件 4.1 电子邮件系统概述 4.2 简单邮件传送…...

MobPush:Android客户端SDK厂商通道回执配置指南
华为厂商回执配置 登录华为AppGallery Connect网站。在左侧菜单点击增长 - 推送服务,进入推送服务页面后,点击配置页签,检查应用回执状态,如未开通请点击右侧开通按钮。 如已开通,点击修改按钮,弹出“选择…...

Karmada: Open, Multi-Cloud, Multi-Cluster Kubernetes Orchestration
Karmada是一个开源的多云应用编排和管理平台,旨在帮助用户在多个云提供商之间无缝地部署、编排和管理应用程序。 Karmada(Kubernetes Armada)是一个Kubernetes管理系统,它使您能够在多个Kubernetes集群和云环境中运行云原生应用程…...

arcgis拓扑检查
不能有悬挂点 不能有伪结点***路网处理很重要,看研究吧。 一直默认到最后。 导入要素类,单个 toupu2右键新建拓扑(T) 一般选不能有悬挂点,不能重叠。 一路默认 是 拉进图层可视化 线要素的话记得添加字段length&#…...

icp许可证 办理流程(icp资质申请条件)
icp许可证 办理流程(icp资质申请条件)是什么? ICP经营许可证是可以线上无忧办理的,包下证,流程也很简单,只需要你提供企业营业执照、法人身份证这些基础材料就可以。加急10-20工作日拿证,普通20-60工作日拿证。 在了解…...

三菱PLC 控制灯一秒钟交替闪烁
三菱PLC中常用的特殊继电器: M8000 上电一直ON标志 M8002 上电导通一次 M8004 PLC出错 M8005 PLC备用电池电量低标志 M8011 10ms时钟脉冲 M8012 100ms时钟脉冲 M8013 1s时钟脉冲 M8014 1min时钟脉冲 M8034…...

金融数据库的战场,太平洋保险和OceanBase打了场胜仗
点击关注 文丨刘雨琦 “数据库的国产替代,必须经过严格的考虑,保证不会出错,所以大多数企业的领导层选择按兵不动或者简单扩容。因为不换就不会错,选了很久如果选错,还可能会出现重大事故。” 某银行数据库技术人员…...

IP协议【图解TCP/IP(笔记九)】
文章目录 IP即网际协议IP相当于OSI参考模型的第3层网络层与数据链路层的关系 IP基础知识IP地址属于网络层地址路由控制■ 发送数据至最终目标地址■ 路由控制表 数据链路的抽象化IP属于面向无连接型 IP即网际协议 TCP/IP的心脏是互联网层。这一层主要由IP(Internet…...
C#仿热血江湖
目录 1 定义属性 2 GClass86_0 3 Int32 4 List 5 NpcID 定义属性 private int _NpcID; private GClass86 gclass86_0 = new GClass86(); private int int_0;...
Nginx静态资源部署
要在 Nginx 上部署静态资源,可以按照以下步骤进行操作: 确保已经安装并配置好 Nginx。如果还没有安装,可以参考 Nginx 的官方文档进行安装和配置。 将静态资源文件复制到 Nginx 的默认静态文件目录下。默认情况下,Nginx 的静态文…...

javaee jstl表达式
jstl是el表达式的扩展 使用jstl需要添加jar包 package com.test.servlet;import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;import javax.servlet.ServletException; import javax.servlet…...
ChatGPT是否具有记忆能力?
ChatGPT在某种程度上具有记忆能力,但它的记忆能力有限且不像人类的记忆那样全面和持久。以下是对ChatGPT的记忆能力的详细分析: 1. 上下文记忆:ChatGPT可以在对话过程中记住先前的对话历史,以便更好地理解和回应后续的问题。通过…...

ARP协议(地址分析协议)
系列文章目录 数通王国历险记(4) 目录 前言 一,什么是地址解析协议(ARP) 二,封装和解封装 三,为什么需要地址解析协议(ARP) 四,ARP的验证实验 4.1&#x…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...

力扣热题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…...
[USACO23FEB] Bakery S
题目描述 Bessie 开了一家面包店! 在她的面包店里,Bessie 有一个烤箱,可以在 t C t_C tC 的时间内生产一块饼干或在 t M t_M tM 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC,tM≤109)。由于空间…...

Java后端检查空条件查询
通过抛出运行异常:throw new RuntimeException("请输入查询条件!");BranchWarehouseServiceImpl.java // 查询试剂交易(入库/出库)记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...
起重机起升机构的安全装置有哪些?
起重机起升机构的安全装置是保障吊装作业安全的关键部件,主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理: 一、超载保护装置(核心安全装置) 1. 起重量限制器 功能:实时监测起升载荷&a…...