首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

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

  • 25-02-22 02:41
  • 2120
  • 8011
blog.csdn.net

目录

Vue优化路径

一、使用key

二、使用冻结对象

三、使用函数式组件

四、使用计算属性

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

六、保持对象引用稳定

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

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

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

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

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

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

八、使用延迟装载(defer)

九、使用keep-alive

十、长列表优化

十一、打包体积优化

十二、总结与相关资源


Vue优化路径

一、使用key

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

二、使用冻结对象

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

  1. var obj = { a : 1, b : 2}
  2. Object.freeze(obj)
  3. obj.a = 3 // 无效,obg.a依然为1
  4. // 此时obj的属性无法访问,自然也无法通过Object.defineProperty来实现响应式
  5. Object.isFrozen(obj) // 返回true,检查是否冻结

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

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

  1. data() {
  2. return{
  3. normalDatas: [],
  4. freezeDatas: [],
  5. };
  6. },
  7. methods: {
  8. loadNormalDatas(){
  9. this.normalDatas = this.getDatas(); console.log("normalDatas", this.normalDatas);
  10. },
  11. loadFrozenDatas() {
  12. this.freezeDatas = Object.freeze(this.getDatas()); console.log("freezeDatas", this.freezeDatas);
  13. },
  14. getDatas(){
  15. const result = [];
  16. for (var i = 0; i < 1000000; i++) {
  17. result.push({
  18. id: i,
  19. name:`name${i}`,
  20. address:{
  21. city:`city${i}`,
  22. province:`province${i}`,
  23. },
  24. });
  25. }
  26. return result;
  27. },
  28. }

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

属性描述符详情请看:属性描述符初探——Vue实现数据劫持的基础

三、使用函数式组件

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

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

  1. // Vue 2中的函数式组件:
  2. Vue.component('my-functional-component', {
  3. functional: true,
  4. render: function (createElement, context) {
  5. // 使用createElement创建元素
  6. return createElement('div', context.props.text);
  7. }
  8. });
  9. // Vue 3中的函数式组件:
  10. import { h, FunctionalComponent } from 'vue';
  11. const MyFunctionalComponent: FunctionalComponent = (props, { slots }) => {
  12. return h('div', props.text, slots().default);
  13. };
  14. export default MyFunctionalComponent;

四、使用计算属性

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

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

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

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

六、保持对象引用稳定

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

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

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

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

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

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

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

  1. function hasChanged(x : unknown, y : unknown) :boolean{
  2. if (x === y){
  3. return x === 0 && 1 / x !== 1 / (y as number)
  4. } else {
  5. return x === x || y === y
  6. }
  7. }

        这里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中的