5年vue开发经验,我总结出了这些性能优化技巧

903 阅读4分钟

一、v-for优化

1.1 使用key

使用v-for渲染列表时,可以通过添加合理的key来优化性能:

  • 不要用index作为key
  • 不要用Math.random()作为key,这个和index效果一样
  • 一般用唯一的id作为key

这个是因为vue在重新渲染列表时,会将标签(比如div span等)+ key前后都相同的节点作为相同节点,会直接进行复用虚拟节点,提升性能。

1.2 v-for和v-if不要连用

由于v-for的优先级高于v-if,所以会在每次迭代时执行 v-if的判断,影响性能。

错误写法:

<template>
  <div>
    <li v-if="list.length > 0" v-for="item in list" :key="item.id">
      {{ item.name }}
    </li>
    <p v-else>列表为空</p>
  </div>
</template>

正确写法:

<template>
  <div>
    <template v-if="list.length > 0">
      <li v-for="item in list" :key="item.id">
        {{ item.name }}
      </li>
    </template>
    <p v-else>列表为空</p>
  </div>
</template>

这里再额外提一下,如果列表太长也会影响性能,可以使用vue-virtual-scroller等库实现虚拟列表来提升性能。

二、合理使用v-if和v-show

  1. v-if:用在组件/DOM上,控制组件/DOM的创建和销毁。
  2. v-show:用在组件/DOM上,控制组件根节点/DOM的CSSdisplay属性。正因为如此,v-show不能用来template空标签上

大部分情况下,使用v-if可以避免不必要的DOM占用、组件开销,而频繁操作/需要保留状态才会使用v-show

<!-- 需要频繁显示/隐藏 -->
<div v-show="isVisible">频繁切换的内容</div>

<!-- 偶尔才会显示的内容 -->
<div v-if="isVisible">按需渲染的内容</div>

三、组件级别的性能优化

3.1 细粒度的组件拆分

vue在重新渲染时两个特点,一个是异步更新,一个是组件级更新/批量更新,异步更新就是指修改了响应式数据之后,会通过nextTick进行更新,组件级更新指的是修改了响应式数据之后,vue的更新是按组件的粒度来进行更新,而批量更新指的是,同一个组件的数据在同一时间改了多次,只会批量更新一次

3.2 keep-alive缓存

如果页面跳转到其它页面后,希望back回到当前页面时不希望重新加载页面,或者需要保留滚动条状态,这时候可以使用vue提供的内部缓存组件keep-alive缓存组件,提升页面性能和体验。

3.3 避免全局组件滥用

全局组件会始终存在于内存中,减少全局注册,使用局部注册提高内存利用率。

3.4 使用函数式组件functional

函数式组件的特点如下:

  • 无状态
  • 没有实例,当然也没有this上下文

如果一个组件只是接收props然后进行渲染,这样就可以将组件标记为functional,也就是函数式组件,使用函数式组件的优点是可以减少组件创建开销

Vue.component('functional-component', {
  functional: true,
  // Props 是可选的
  props: {
    // ...
  },
  // 为了弥补缺少的实例
  // 提供第二个参数作为上下文
  render: function (createElement, context) {
    // ...
  }
})

3.5 异步组件/路由懒加载

使用异步组件和路由懒加载可以实现按需加载,提升加载速度。

四、Object.freeze

vue内部会把data中的数据用Object.defineProperty重写getset,所以如果是一些不会变化的静态数据,可以用Object.freeze进行数据冻结,这样vue就不会用Object.defineProperty去处理这些数据了,同时这些数据变化时,也不会执行更新页面的逻辑了,这样提升了vue的初始化和更新性能。

export default {
  data() {
    return {
      obj: Object.freeze({ a: 1, b: { c: 2 }})
    };
  }
};

五、合理使用computed和Watch

computed具有缓存的特点,当依赖没重新变化不会重新计算,提升性能。

Watch使用太多会损耗性能,建议少用,比如换成监听input/change事件回调,尤其是deep: true会深度监听,必要时再使用。

六、事件监听的优化

6.1 v-on按需监听

我们可以使用v-on按需监听组件,比如封装一个upload组件时,如果不需要拖拽功能,就不需要监听dragstartdragover等事件了。

<template>
  <div v-on="events" draggable>
    123113
   </div>
</template>
<script>
export default {
  props: {
    // 是否支持拖拽
    isDrag: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      events: {},
    }
  },
  created() {
    if (this.isDrag) {
      this.events = {
        dragstart: this.onDragStart,
        dragover: this.onDragOver,
      }
    }
  },
  methods: {
    onDragStart() {
      console.log('onDragStart')
    },
    onDragOver() {
      console.log('onDragOver')
    },
  }
}
</script>

6.2 @click.stop、@click.capture

合理使用@click.stop@click.capture修饰符可以控制时间传播,提升性能。

6.3 v-once

使用v-once可以将节点标记为静态节点Vue在编译阶段会对静态节点进行静态提升,同时将静态部分缓存起来,在重新渲染时直接复用 ,提升页面更新性能。

6.4 防抖和节流

使用防抖和节流,可以控制事件触发的频率,从而提升页面性能。比如输入框搜索场景可以用防抖,监听滚动事件实现页面懒加载的时候,可以使用节流。

小结

以上就是我结合自己5年的前端vue使用经验,再加上对vue源码的理解,总结出来的一些vue性能优化技巧,当然很多优化都不能显著提升性能,但我还是希望从小处着手,让自己的vue项目写的更加合理,一点一滴的优化慢慢就能累计成大优化。