Vue 性能革命:揭秘前端优化的终极技巧;Vue优化技巧,解决Vue项目卡顿问题

举报
watermelo37 发表于 2025/07/31 22:31:13 2025/07/31
【摘要】 ​Vue优化路径​​一、使用key        也就是使用v-for这样通过循环生成的列表,应给每个列表项一个稳定且唯一的key,这样有利于在列表变动时,尽量少的删除、新增、改动元素。二、使用冻结对象        在不需要改动的数据时(比如只读的数据:面向顾客的商品列表等),将对象冻结。例如:var obj = { a : 1, b : 2}Object.freeze(obj)obj.a...

Vue优化路径

一、使用key

        也就是使用v-for这样通过循环生成的列表,应给每个列表项一个稳定且唯一的key,这样有利于在列表变动时,尽量少的删除、新增、改动元素。

二、使用冻结对象

        在不需要改动的数据时(比如只读的数据:面向顾客的商品列表等),将对象冻结。例如:

var obj = { a : 1, b : 2}

Object.freeze(obj)

obj.a = 3 // 无效,obg.a依然为1

// 此时obj的属性无法访问,自然也无法通过Object.defineProperty来实现响应式

Object.isFrozen(obj) // 返回true,检查是否冻结

        冻结的对象不会被响应化,节约了observe该对象每个属性的资源(添加getter和setter)

        举一个例子,可以做一个demo实际体验一下效率的区别,做个页面放两个按钮,分别绑定loadFrozenDatas和loadNormalDatas方法,就能明显感受到生成同样的数据,冻结的对象生成速度显著快于不冻结的对象生成。

data() {
    return{
        normalDatas: [],
        freezeDatas: [],
    };
},
methods: {
    loadNormalDatas(){
        this.normalDatas = this.getDatas(); console.log("normalDatas", this.normalDatas);
    },
    loadFrozenDatas() {
        this.freezeDatas = Object.freeze(this.getDatas()); console.log("freezeDatas", this.freezeDatas);
    },
    getDatas(){
        const result = [];
        for (var i = 0; i < 1000000; i++) {
            result.push({
                id: i,
                name:`name${i}`,
                address:{
                    city:`city${i}`,
                    province:`province${i}`,
                },
            });
        }
        return result;
    },
}

observe中会调用Object.defineProperty(),通过属性描述符为对象的每个属性实现响应式

三、使用函数式组件

        在Vue.js中,函数式组件是一种没有状态和实例的概念的组件。函数式组件主要用于声明性地描述UI,它们接受 props 作为输入,并返回一个Vue元素树作为输出。

        函数式组件不会通过new VueComponent生成新的vue实例,不会加入到vue的组件树中,只做页面渲染,节省性能。

// Vue 2中的函数式组件:

Vue.component('my-functional-component', {
  functional: true,
  render: function (createElement, context) {
    // 使用createElement创建元素
    return createElement('div', context.props.text);
  }
});


// Vue 3中的函数式组件:

import { h, FunctionalComponent } from 'vue';

const MyFunctionalComponent: FunctionalComponent = (props, { slots }) => {
  return h('div', props.text, slots().default);
};

export default MyFunctionalComponent;

四、使用计算属性

        计算属性可以缓存(只有所依赖的数据变化了才会重新计算),如果模版中数据会使用多次,就可以使用计算属性。

五、使用非实时绑定的表单项

        双向绑定会导致任意一端修改数据均会导致重渲染rerender,在不需要双向绑定的位置(比如只开放只读数据)或者不需要保持实时数据双向绑定的情况下(比如输入框内容和页面某元素绑定,输入过程中每按一次键盘都会导致一次重新渲染)不使用v-model。

        也可以通过v-model.lazy来允许某一时间内数据与表单内容不一致,也就是从监听@input变成了监听@change。

六、保持对象引用稳定

6.1、保持对象引用稳定定义

        大多数情况下,vue触发重渲染的时机是依赖数据发生变化的时机,若数据没有变化,哪怕重新给数据赋值,vue也不会做出反应。

        因此,哪怕读取属性所属的对象值没变,但是引用变了,也会导致页面重新渲染。 

6.2、保持对象引用稳定与不稳定的例子

        现在页面上渲染了一个表格,由一系列对象数据生成。如果要在数据库增加一行。那么读取数据库增加的数据,并将其添加到现有的表格数据中,效率会比直接从数据库读取全部数据,然后赋值给表格绑定的数据上要高。

        因为读取增加的数据,然后修改表格绑定的数据,只有变化的数据会重新渲染,原先有的表格行不会重渲染,可如果直接把增加后的全部数据(一个引用不同的新对象)赋值给表格绑定的数据,就会导致所有行全部重新渲染,哪怕大多数行数据并没有变化

6.3、vue2判断数据是否变化是通过hasChanged函数实现的

function hasChanged(x : unknown, y : unknown) :boolean{
  if (x === y){
    return x === 0 && 1 / x !== 1 / (y as number)
  } else {
    return x === x || y === y
  }
}

        这里x与y分别是新值和旧值。

        正常情况下,如果x===y,代表没有改变,返回false,反之则返回true。

①为什么在x === y成立的时候,还要做一个return x === 0 && 1 / x !== 1 / (y as number)的判断?

        +0 === -0的判断恒为true,但二者实际不相等。所以先判断x是否为0+或0-,如果不是,则直接触发短路返回false,如果是,就通过求倒数,比较倒数是否相等,如果均为0+或均为0-,则依然返回false,若倒数为Infinity和-Infinity,这样就会返回true,从而排除从0+变为0-,但是却新旧值却相等的情况。

②为什么在 x === y 不成立的时候,还要做一个x === x || y === y的判断?

        因为如果NaN === NaN的判断恒为false,所以哪怕不相等,还要做一下自判断,若新旧值都是NaN,则返回false。排除x与y都为NaN,但是新旧值却不相等的情况。

七、使用v-show替代v-if

        对于频繁切换显示状态的元素,使用v-show可以保证虚拟dom树的稳定,尤其是对于那些内部包含大量dom元素的节点,这一点极其重要。

        DOM树只与布局有关,与显示与否无关。使用v-show渲染的元素,不管返回值是什么,都会添加到dom树中,但是使用v-if渲染的元素,只有为true的时候才会添加到DOM树中。

八、使用延迟装载(defer)

        HTML中的<script>标签有一个可选的defer属性。当脚本设置了defer属性后,它会被告知浏览器在文档解析完成后再执行这个脚本,而不是立即执行。

        对于图片和其他资源,可以使用 v-lazy-image 或 v-lazy-component 这样的 Vue 指令来实现懒加载。

<!-- 在模板中使用 -->
<img v-lazy="imageSrc" alt="Lazy Image">

        使用像 vue-lazyload 这样的库来实现图片和组件的懒加载。 

// 安装 vue-lazyload
npm install vue-lazyload --save

// 在 main.js 中使用
import Vue from 'vue';
import VueLazyload from 'vue-lazyload';

Vue.use(VueLazyload, {
  preLoad: 1.64,
  error: 'error.png',
  loading: 'loading.png',
  attempt: 1
});

九、使用keep-alive

        keep-alive 是 Vue 的一个内置组件,用于缓存不活动的组件实例,避免重复创建和销毁组件,从而提高性能。这在单页面应用(SPA)中特别有用,可以保持用户状态和避免不必要的重新渲染。

<!-- 在路由出口使用 -->
<router-view v-if="$route.meta.keepAlive"></router-view>
<keep-alive>
  <router-view v-if="!$route.meta.keepAlive"></router-view>
</keep-alive>

        这里会根据路由的 meta 属性决定是否使用 keep-alive。

十、长列表优化

        海量数据渲染容易导致卡顿,除了可以运用第六点保持引用对象稳定外,Vue还提供了几种方法来优化长列表的渲染:

  • 虚拟滚动(Virtual Scrolling):只渲染可视区域内的元素,而不是渲染整个列表。可以使用 vue-virtual-scroll-list 或 vue-virtual-scroller 等库来实现。
  • 分页或无限滚动:将数据分批次加载,而不是一次性加载所有数据。
  • 节流(Throttle)和防抖(Debounce):在处理滚动事件等频繁触发的操作时,使用节流或防抖技术减少事件处理的频率。

        此外,element plus也提供了虚拟化组件,用来处理海量数据的渲染问题

十一、打包体积优

        减少最终打包文件的大小可以提高应用的加载速度和性能。常见方法包括:

  1. 代码分割(Code Splitting):使用 Webpack 的动态 import() 语法来实现代码分割,只加载用户实际需要的代码。
  2. Tree Shaking:移除未使用的代码,Webpack 等现代打包工具可以自动进行 Tree Shaking
  3. 使用 Vue CLI 的优化选项:Vue CLI 提供了多种优化配置,如 vue-cli-service build --report 可以生成报告,帮助分析打包体积。
  4. 移除 console.log:在生产环境中,确保移除所有的 console.log 语句,因为它们会增加打包体积。
  5. 使用 Terser 或 UglifyJS 压缩 JavaScript:这些工具可以压缩 JavaScript 代码,减少文件大小。

十二、总结与相关资源

        Vue在处理少量数据和有限dom的情况下技术已经非常成熟了,但现在随着AI时代的到来,海量数据场景会越来越多,Vue优化技巧也是必备技能。

        博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

        更多优质内容,请关注

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。