Code前端首页关于Code前端联系我们

Vue3性能优化日常开发必做的实用技巧有哪些?

terry 10小时前 阅读数 127 #Vue

很多开发者可能觉得,Vue3的响应式系统已经升级成Proxy了,天生就比Vue2快很多,不用再管性能问题——但实际上,Proxy只是解决了核心响应式的瓶颈,要是在组件设计、模板编写上踩坑,照样会让页面卡顿,比如列表滚动掉帧、弹窗打开延迟、数据量大时页面白屏,这几年做项目和帮同行排查性能问题,积累了不少好用的技巧,今天整理成清晰的内容,都是日常开发随手就能改、改完立刻能看到效果的。

响应式系统的「减负」技巧

Proxy虽然强大,但也不是什么数据都要包成响应式的,包得越多,数据变化时的依赖追踪和更新通知就越重,这部分是很多开发者最容易忽略的,但调整起来性价比最高。

区分「真·响应式」和「静态数据」

比如做后台管理系统的侧边栏导航,或者固定的组件配置项(像echarts的基础option,除非业务要完全换图表类型,否则一般只改series),这些数据完全不需要响应式,Vue3里怎么处理呢? 可以用ref(null)初始化,然后直接赋值给.value的对象,但这个赋值的过程不要用reactive或者ref的嵌套包装;更规范的是用markRaw标记,告诉Vue3:“这个对象/数组不管怎么变,你都别管它的响应式”,比如固定的导航数组:

import { markRaw } from 'vue'
const sidebarNav = markRaw([
  { name: '首页', path: '/' },
  { name: '用户管理', path: '/users' }
])

这样写,不管是修改数组里的path还是name,都不会触发Vue的响应式更新,但视图本来也不用跟着这些固定数据变,反而省了很多追踪的开销。

深层嵌套数据按需响应式

有些业务场景,比如商品详情页的商品属性,可能有几十层嵌套,但只有价格、库存这几个字段需要实时更新,其他都是静态展示的,这时候如果把整个属性对象包成reactive,每次修改价格,Vue都会遍历整个对象的依赖,效率很低。 怎么办?可以拆分响应式的层级:把整个商品对象用ref或者浅的reactive(不过浅的话直接属性赋值可能有坑,推荐ref存对象加markRaw包静态子属性),然后只把需要实时更新的字段单独拎出来做响应式,或者用shallowReactive配合显式的triggerRef/trigger手动触发更新。

import { shallowReactive, trigger } from 'vue'
// 整个商品用浅响应式,只有直接属性(price/stock)变化才触发
const product = shallowReactive({
  id: 1001,
  price: 99,
  stock: 50,
  // 静态属性用markRaw
  specs: markRaw({
    color: '白色',
    size: 'L',
    details: {
      material: '纯棉',
      weight: '200g'
    }
  })
})
// 如果必须修改specs里的某个静态属性后的子属性(比如特殊需求改details.weight后展示?其实这种需求很少,尽量避免),可以手动触发
function updateDetailWeight() {
  product.specs.details.weight = '250g'
  // 手动指定product.specs.details这个路径的更新
  trigger(product, 'specs')
}

不过还是那句话,手动触发更新只适用于极特殊的情况,能不用就不用,核心还是「静态数据绝不包响应式」。

组件渲染的「节流」和「懒加载」

组件是Vue页面的基本单位,优化组件的渲染方式,能直接减少DOM操作和重新渲染的次数。

用v-if和v-for的正确顺序,再补个key值

Vue2里一直强调v-for不能和v-if放在同一个标签上,因为Vue会先执行v-for再执行v-if,导致很多不必要的循环,Vue3虽然处理逻辑优化了(官方文档说现在会优先处理v-if,但其实如果v-if的条件依赖v-for的变量,还是会先循环),但为了稳妥,也为了更符合逻辑,还是分开写比较好——比如把v-if放在外层的容器标签,或者用计算属性先过滤掉不需要渲染的数组项。 key值的选择也很重要,千万不要用index!这个很多人知道,但有时候图方便还是会用,用index当key的话,数组里的元素一旦发生增删改(比如中间插入一个元素),后面所有元素的key都会变,Vue会把后面所有的DOM都删掉再重建,开销特别大,应该用数据里唯一的、稳定的属性当key,比如id、uuid这些,如果数据里实在没有唯一标识,也可以自己生成一个临时的,但要确保在渲染期间不变化。

组件的懒加载和异步加载

页面加载的时候,不需要把所有组件都加载进来,只加载当前可见区域或者用户马上要用到的组件就行,比如后台管理系统的标签页内容、详情页的折叠面板、弹窗组件,这些都可以做懒加载或者异步加载。 Vue3里的异步加载组件写法很简单,用defineAsyncComponent就行,还可以加加载中、加载失败的状态组件,提升用户体验:

import { defineAsyncComponent } from 'vue'
const UserDetailModal = defineAsyncComponent({
  loader: () => import('./UserDetailModal.vue'),
  loadingComponent: () => import('./Loading.vue'),
  errorComponent: () => import('./Error.vue'),
  delay: 200, // 延迟200ms显示加载组件,避免快速加载时的闪烁
  timeout: 3000 // 3秒没加载出来显示错误组件
})

对于长列表(比如超过100条数据的列表),可以用虚拟滚动来懒加载可见区域的组件——Vue3官方生态里的vue-virtual-scroller或者vue-virtual-scroll-list都挺好用的,几行代码就能让长列表滚动如丝般顺滑,虚拟滚动的原理其实很简单:不管数据有多少条,只渲染当前可见区域的十几二十条DOM,列表滚动的时候,动态替换这些DOM里的内容,同时调整容器的高度,让用户感觉像是在渲染所有数据。

其他容易忽略的细节优化

除了响应式和组件渲染,还有一些小细节,改起来也很简单,但加起来效果也很明显。

避免在模板里写复杂的计算逻辑

很多开发者喜欢在模板里直接写{{ a + b * c / d }}或者{{ list.filter(item => item.age > 18).map(item => item.name).join(', ') }},这样写虽然方便,但每次组件重新渲染(哪怕和这个计算逻辑无关的数据变了),都会重新执行一遍这个复杂的计算,效率很低。 应该把复杂的计算逻辑放到computed里,computed有缓存,只有依赖的响应式数据变了,才会重新计算,比如刚才的列表过滤和映射:

import { computed } from 'vue'
const userList = ref([...])
const adultNames = computed(() => {
  return userList.value.filter(item => item.age > 18).map(item => item.name).join(', ')
})

这样写,只有userList里的元素或者元素的age属性变了,adultNames才会重新计算,其他时候都是用的缓存值。

用v-once标记一次性渲染的内容渲染一次之后就永远不会变了,比如网站的版权信息、文章的标题(如果是静态文章的话),可以用v-once标记,告诉Vue3:“这个DOM渲染完就别管它了,永远不用更新”,v-once可以用在单个标签上,也可以用在一个组件或者一段模板上:

<!-- 单个标签 -->
<p v-once>© 2024 某某科技有限公司 版权所有</p>
<!-- 组件 -->
<StaticArticle v-once :content="articleContent" />
<!-- 一段模板 -->
<template v-once>
  <h1>{{ articleTitle }}</h1>
  <div class="article-meta">{{ articleAuthor }} · {{ articlePublishTime }}</div>
</template>

开启生产模式

最后一个超级简单但超级重要的细节:上线的时候一定要开启Vue3的生产模式!生产模式下,Vue会去掉所有的警告信息、调试信息,还会做很多编译优化和代码压缩,性能能提升好几倍。 不同的构建工具开启生产模式的方式不一样,比如用Vite的话,直接执行npm run build就行;用Webpack的话,设置NODE_ENV=production,开启生产模式之后,可以在浏览器的控制台里看看有没有Vue的警告或者提示,如果没有的话,就说明开启成功了。

就是我整理的Vue3性能优化日常开发必做的实用技巧,都是经过实战验证的,改完立刻能看到效果,其实性能优化不是只有遇到问题的时候才做,应该养成良好的开发习惯,从写第一行代码开始就注意这些细节,这样才能写出性能优秀的Vue3应用。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门