🔥这 10 个 Vue3 性能优化技巧,藏太深了,建议保存!

说实话,Vue3 出来这么久,光 Composition API 和响应式就够大家研究半天了。但性能优化这块,很多人还停留在"用 v-if 替代 v-show""不要重复渲染"这种 level。

今天我把这段时间优化项目中踩过的坑、用过的 trick,总结成 10 条 Vue3 性能优化技巧,有些细节藏得太深,建议你直接收藏起来,项目上线前一条条过一遍。


1️⃣ defineComponent 别乱用,能用 SFC 就别函数式

Vue3 支持函数式组件,但在大量场景中,过度使用 defineComponent() + setup() 可能引入不必要的闭包和响应式计算,影响初始化性能。

建议 :通用组件写 SFC(单文件组件)+ <script setup>,比闭包组件更易优化、缓存、调试。


2️⃣ watchEffect 是利器也是地雷,别用在 layout 逻辑上

很多人为了方便直接把 DOM 操作放在 watchEffect 里。结果组件一更新、依赖变动,就疯狂触发。

ts 复制代码
watchEffect(() => {
  el.value.scrollTop = 0 // ❌:这是副作用,不应该放在响应式追踪中
})

正确做法 :用 watch(),带 debounce,控制副作用频率。


3️⃣ v-for 列表的 key 千万别写错:index 是性能杀手

这一条大家可能听过,但还是会踩。用 index 做 key,在动态更新时 Vue 无法复用 DOM,直接销毁重建。

html 复制代码
<!-- ❌ -->
<div v-for="(item, index) in list" :key="index">{{ item.name }}</div>

<!-- ✅ -->
<div v-for="item in list" :key="item.id">{{ item.name }}</div>

尤其是在频繁更新列表的数据可视化、表格组件中,key 写错会直接触发 DOM 回流重排


4️⃣ 慎用 computed 返回复杂对象,响应式追踪炸裂

你写一个 computed(() => complexObj),Vue 会追踪整个对象。如果里面有大量字段、方法,性能直接起飞。

ts 复制代码
// ❌:容易让响应式系统过度追踪
const userMap = computed(() => new Map(users.value.map(u => [u.id, u])))

// ✅:改成 flat array,或者只计算需要的字段

5️⃣ 不要把 ref([]) 和大对象直接暴露给多个组件使用

误用场景:你写了一个 ref([]),然后传给多个子组件共享。结果改了一项,整个数组被追踪一次,导致每个使用者都被动更新。

解决方法

  • shallowRef() 包一层,手动控制更新
  • 或者用 Proxy + 自定义 getter 精确追踪字段

6️⃣ 大量动态组件不要用 <component :is="xxx" />,性能崩溃

动态组件虽然香,但会带来:

  • 挂载/卸载频繁
  • 缓存无效
  • 状态丢失

建议替代方案

html 复制代码
<keep-alive>
  <MyTabA v-if="tab === 'a'" />
  <MyTabB v-else-if="tab === 'b'" />
</keep-alive>

显式声明组件 + keep-alive,提升切换性能。


7️⃣ 自定义指令别滥用,mounted 中 DOM 读写容易造成布局抖动

比如做 tooltip、position 定位的指令,如果在 mounted() 中读取 getBoundingClientRect(),会触发强制重排。

解决方式

ts 复制代码
requestAnimationFrame(() => {
  // 延迟读取,防止抖动
})

8️⃣ 小心 v-model@update:modelValue 的双向绑定递归问题

Vue3 虽然简化了 v-model,但双向绑定 + 父组件 watch 一不小心就会触发递归。

实战建议

ts 复制代码
// watch 里加判断
watch(() => props.modelValue, (val) => {
  if (val !== localVal.value) localVal.value = val
})

9️⃣ SSR/预渲染页面时,尽量避免使用异步的响应式数据源

很多人会直接在 setup() 里写异步请求,然后用于组件渲染。SSR 下可能直接输出 [object Promise] 或空数据。

建议

  • SSR 页面用 async setup() + await fetch() + return 渲染数据
  • 或者预取数据放在 <script> 里注入,全局 hydration 时解析

🔟 用好 devtools,不只是调试,还能看"慢组件"

Vue Devtools 有一个隐藏用法是:看每个组件的 render 次数和 diff 触发点

打开 Vue Devtools,切换到"性能"或"组件树",能看到组件被反复更新的次数,尤其是:

  • 有大图渲染的地方
  • 有复杂 slot 的地方
  • 大型表单组件

搭配 markRaw()shallowReactive() 甚至 defineAsyncComponent() 都能做 lazy load。


🧠性能不是优化出来的,是设计出来的

Vue3 给了我们非常灵活的响应式系统,但滥用比不用更可怕。

建议你:

  • 统一响应式策略(ref + computed + watch
  • 统一组件通信方式(props or context)
  • 加上埋点 + devtools 报表,定期做 render 追踪

📌 你可以继续看我的系列文章

相关推荐
独立开阀者_FwtCoder1 分钟前
Nginx 通过匹配 Cookie 将请求定向到特定服务器
java·vue.js·后端
哒哒哒52852025 分钟前
HTTP缓存
前端·面试
T___27 分钟前
从入门到放弃?带你重新认识 Headless UI
前端·设计模式
wordbaby29 分钟前
React Router 中调用 Actions 的三种方式详解
前端·react.js
黄丽萍35 分钟前
前端Vue3项目代码开发规范
前端
葬送的代码人生37 分钟前
AI Coding→像素飞机大冒险:一个让你又爱又恨的小游戏
javascript·设计模式·ai编程
curdcv_po38 分钟前
🏄公司报销,培养我成一名 WebGL 工程师⛵️
前端
Jolyne_1 小时前
前端常用的树处理方法总结
前端·算法·面试
wordbaby1 小时前
后端的力量,前端的体验:React Router Server Action 的魔力
前端·react.js
Alang1 小时前
Mac Mini M4 16G 内存本地大模型性能横评:9 款模型实测对比
前端·llm·aigc