vue - 常见的性能优化

news2025/3/4 22:54:39

在这里插入图片描述

文章目录

    • 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>
  <li
    v-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">
  <li
    v-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=false
        to.meta.keepAlive=false
        next()
    }
},
在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 = null
      removeEventListener('touchmove', this.touchmove, false)
    }
}
</script>

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

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

相关文章

Selenium如何定位动态元素?

在经常做自动化过程中&#xff0c;我们没有打开新页面、没有alert、没有frame、加了挺好的等待时间&#xff0c;但是还是定位不到元素&#xff1f;很有可能是你要定位的元素的属性是动态的&#xff0c;即每次打开页面&#xff0c;这个元素的id或者class等元素属性是动态生成的。…

低代码平台缓解了程序员日渐不足的尴尬局面

编者按&#xff1a;如今即便是编程语言学习难度的降低&#xff0c;也不足以跟上计算机应用的快速发展&#xff0c;为了提高软件开发效率&#xff0c;满足市场需求&#xff0c;低代码平台的可视化开发、组件化和框架化降低了开发的技术门槛&#xff0c;让更多人能参与到软件开发…

通过SSH的方式连接Git仓库

前置条件 git已经安装。 生成公钥私钥 任意调出 git bash 执行&#xff1a; 回车两次&#xff0c;如果已有则需要覆盖确认 Overwrite ssh-keygen -t rsa -C "your_emailexample.com" 生成后的文件路径&#xff1a; C:/user/你的账户/.ssh下&#xff0c;其中 id…

麒麟信安与派盘互认证成功

麒麟信安是中国领先的信息安全技术服务商&#xff0c;具有自主研发的核心安全技术&#xff0c;致力于为企业等各类用户提供高效、安全、可靠的信息安全防护服务。而派盘是深圳科迈爱康科技有限公司的产品&#xff0c;是一款本地云存储解决方案&#xff0c;支持多平台接入&#…

WPF Prims框架详解

文章目录 前言Prism基本使用Prism选择&#xff0c;DryIoc还是UnityPrism基本框架搭建Prism动态更新View和ViewModel对应关系参数动态更新函数动态绑定 prism新建项目模板region使用事例测试是否限制空间 消息订阅如何使用消息订阅使用建议 路由导航对话框/弹窗功能实现代码 前言…

国内什么牌子的ipad手写笔好用?电容笔性价比高推荐

随着平板电脑在校园、办公室中的应用越来越广泛&#xff0c;需要一种具有良好性能的电容笔。苹果品牌原装的这支电容笔&#xff0c;虽然功能很强&#xff0c;但因为其的价格实在是太贵了&#xff0c;所以只是用来学习记笔记&#xff0c;实在是太浪费了。所以&#xff0c;哪个电…

JavaSwing+MySQL的飞机订票系统(内含oracle版本)

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/88055544 JDK1.8 MySQL5.7 功能&#xff1a;接收客户端发来的数据、处理客户端发来的数据、发送数据包到客户端&#xff1b;客户端&#xff1a;查询所有航班的信息、查看自己所定的票、订票…

Day 60 小结

1.惰性学习&#xff08;消极学习&#xff09;&#xff1a;在训练数据集的时候不会创建目标函数&#xff0c;只是简单将训练样本存储。后期需要对新样本进行判断的时候分析新样本和已存储的样本之间的关系&#xff0c;并以此确定新样本的输出值。例如&#xff1a;knn算法。 2.急…

LeetCode:4. 寻找两个正序数组的中位数

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340; 算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 题解目录 一、&#x1f331;[4. 寻找两个正序数组的中位数](https://leetcode.cn/proble…

微信朋友圈同步你知道怎么设置吗?

微信关于朋友圈同步 其实没有什么其他方法 但是不想一直复制粘贴 繁琐又麻烦 对于要发布很多条的情况下 就很不方便 如果是有可以同步朋友圈的功能 我们可以先选择一个好友 然后设置好跟圈任务 好友发啥你就会跟TA发出一模一样的朋友圈

CEASC项目环境搭建(训练VisDrone数据集)

CEASC项目环境搭建&#xff08;训练VisDrone数据集&#xff09; 论文地址&#xff1a;https://openaccess.thecvf.com/content/CVPR2023/papers/Du_Adaptive_Sparse_Convolutional_Networks_With_Global_Context_Enhancement_for_Faster_CVPR_2023_paper.pdf Code&#xff1a…

同比环比数据可视化

引言 数据分析和可视化在现代商业环境中变得越来越重要。随着数据的迅速增长&#xff0c;我们需要有效的工具来解释和理解这些数据。 数据可视化提供了一种直观的方式&#xff0c;帮助我们从海量数据中提取有意义的见解&#xff0c;以支持业务决策。 同比环比图作为一种常见的…

AI制图工具丨Midjourney产品功能介绍

了解如何使用Discord上的Midjourney Bot通过简单的文本提示创建自定义图像 Midjourney是一款AI制图工具&#xff0c;只要关键字&#xff0c;就能透过AI算法生成相对应的图片&#xff0c;只需要不到一分钟。 可以选择不同画家的艺术风格&#xff0c;例如安迪华荷、达芬奇、达利…

JavaScript中的JSON

一&#xff1a;分类  简单值&#xff1a;字符串、数值、布尔值和 null 可以在 JSON 中出现&#xff0c;就像在 JavaScript 中一样。特殊 值 undefined 不可以。 对象&#xff1a;第一种复杂数据类型&#xff0c;对象表示有序键/值对。每个值可以是简单值&#xff0c;也可以…

如何通过三级缓存解决 Spring 循环依赖

以下内容基于 Spring6.0.4。 这个其实是一个特别高频的面试题&#xff0c;松哥也一直很想和大家仔细来聊一聊这个话题&#xff0c;网上关于这块的文章很多&#xff0c;但是我一直觉得要把这个问题讲清楚还有点难度&#xff0c;今天我来试一试&#xff0c;看能不能和小伙伴们把…

一张证,三年月薪翻三倍!

18年9月&#xff0c;我获取了PMP&#xff08;项目管理&#xff09;认证&#xff0c;19年6月获取了PgMP&#xff08;项目集群管理&#xff09;认证。考证过程并不是很难&#xff0c;月薪却从1万突破3万&#xff0c;也找到了自己喜欢和擅长的工作领域&#xff0c;获益无穷。 什么…

Navicat 用户权限功能 | 预防 MySQL 删库风险

近期&#xff0c;我们后台收到一位用户的问询&#xff0c;有关于误删库的解决办法。对于企业来说&#xff0c;这可能是一个大事故&#xff01;但幸运的是&#xff0c;该用户在不久之前看了我们的 Navicat 自动备份功能文章&#xff0c;并且实施了数据库备份操作&#xff0c;所以…

如何下载SRA存放在AWS的原始数据

通常&#xff0c;我们都是利用prefetch从NCBI上获取数据&#xff0c;然后用fasterp-dump/fastq-dump 转成fastq。但遗憾的SRA的数据是原数据的有损压缩&#xff0c;比如说我19年参与发表的文章里单细胞数据上传的是3个文件&#xff0c;但是当时的faster-dump/fastq-dump只能拆出…

MongoDB源码安装

文章目录 MongoDB源码安装&#xff1a;注&#xff1a;下载&#xff1a;解压&#xff1a;创建数据目录&#xff1a;创建软链接&#xff1a;创建变量脚本&#xff1a;执行脚本&#xff1a;启动mongodb:检查&#xff1a;连接mongodb&#xff1a; MongoDB源码安装&#xff1a; 注&…

Flutter系列文章-Flutter基础

Flutter是Google推出的一种新的移动应用开发框架&#xff0c;允许开发者使用一套代码库同时开发Android和iOS应用。它的设计理念、框架结构、以及对Widget的使用&#xff0c;都让开发者能更有效率地创建高质量的应用。 一、Flutter设计理念 Flutter的设计理念是“一切皆为Wid…