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

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}...
}

可以看到一开始就判断 configurablefalse 的直接返回不做响应式处理;

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&#xff0c; v-for 遍历避免同时使用 v-if2&#xff0c; 如果需要使用v-for给每项元素绑定事件时 可以使用事件代理**3&#xff0c; 一些数据不做响应式4&#xff0c;一些页面采用keep-alive缓存组件5&#xff0c;第三方UI库按需导入6&#…...

微服务系列文章 之 Nginx服务状态监控的方法

在Nginx的插件模块中有一个模块stub_status可以监控Nginx的一些状态信息&#xff0c;默认安装可能没有这个模块&#xff0c;手动编译的时候加一下即可。 1. 模块安装 先使用命令查看是否已经安装这个模块&#xff1a; [rootihxb123Z nginx]# ./nginx -V (V大写会显示版本号和…...

【网络系统集成】路由器实验

1.实验名称:路由器RIP协议配置 2.实验目的 在PacketTracer中进行模拟实验,配置RIP协议,验证RIP协议更新时间及路由状态变化,加深对路由器RIP协议相关知识的理解与掌握。 3.实验内容 (1)拓扑结构图 (2)ip地址分配与端口分配...

【mac 安装Miniconda】

1.下载Miniconda 注意mac是什么版本&#xff0c;m1下载m1版本 https://docs.conda.io/en/latest/miniconda.html#macos-installers 2.安装Miniconda 在下载文件所在目录下打开终端&#xff0c;输入一下命令&#xff1a; bash Miniconda3-latest-MacOSX-x86_64.sh 一路回车&…...

螺栓疲劳计算-风电行业,参考GL2010, ST0361,1993-1-9

由于不想再重新排版了&#xff0c;于是转成了图片。...

QT学习之旅 - QThread多线程

文章目录 首先是主线程 其次是一个程序 通过一个QThread来放入程序 进阶一点: 手动开启关闭线程俩个线程 其实QT中的thread(线程)是很容易的 首先是主线程 #include "mainwindow.h" #include "ui_mainwindow.h"#include <QDebug>MainWindow::MainWin…...

PROFINET转TCP/IP网关TCP/IP协议的含义是

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

计算机网络基础第六章

一、应用层概述 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网站。在左侧菜单点击增长 - 推送服务&#xff0c;进入推送服务页面后&#xff0c;点击配置页签&#xff0c;检查应用回执状态&#xff0c;如未开通请点击右侧开通按钮。 如已开通&#xff0c;点击修改按钮&#xff0c;弹出“选择…...

Karmada: Open, Multi-Cloud, Multi-Cluster Kubernetes Orchestration

Karmada是一个开源的多云应用编排和管理平台&#xff0c;旨在帮助用户在多个云提供商之间无缝地部署、编排和管理应用程序。 Karmada&#xff08;Kubernetes Armada&#xff09;是一个Kubernetes管理系统&#xff0c;它使您能够在多个Kubernetes集群和云环境中运行云原生应用程…...

arcgis拓扑检查

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

icp许可证 办理流程(icp资质申请条件)

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

三菱PLC 控制灯一秒钟交替闪烁

三菱PLC中常用的特殊继电器&#xff1a; M8000 上电一直ON标志 M8002 上电导通一次 M8004 PLC出错 M8005 PLC备用电池电量低标志 M8011 10ms时钟脉冲 M8012 100ms时钟脉冲 M8013 1s时钟脉冲 M8014 1min时钟脉冲 M8034…...

金融数据库的战场,太平洋保险和OceanBase打了场胜仗

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

IP协议【图解TCP/IP(笔记九)】

文章目录 IP即网际协议IP相当于OSI参考模型的第3层网络层与数据链路层的关系 IP基础知识IP地址属于网络层地址路由控制■ 发送数据至最终目标地址■ 路由控制表 数据链路的抽象化IP属于面向无连接型 IP即网际协议 TCP/IP的心脏是互联网层。这一层主要由IP&#xff08;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 上部署静态资源&#xff0c;可以按照以下步骤进行操作&#xff1a; 确保已经安装并配置好 Nginx。如果还没有安装&#xff0c;可以参考 Nginx 的官方文档进行安装和配置。 将静态资源文件复制到 Nginx 的默认静态文件目录下。默认情况下&#xff0c;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在某种程度上具有记忆能力&#xff0c;但它的记忆能力有限且不像人类的记忆那样全面和持久。以下是对ChatGPT的记忆能力的详细分析&#xff1a; 1. 上下文记忆&#xff1a;ChatGPT可以在对话过程中记住先前的对话历史&#xff0c;以便更好地理解和回应后续的问题。通过…...

ARP协议(地址分析协议)

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

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...

shell脚本质数判断

shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数&#xff09;shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数&#xff09; 思路&#xff1a; 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...