Vue 性能优化(策略 + 示例代码)

📅 发布时间:2026/8/11 19:16:33
Vue 性能优化(策略 + 示例代码) Vue 性能优化策略 示例代码分为编译打包优化、渲染优化、DOM/列表优化、事件内存、网络请求、Vue特有API、工程化兼顾 Vue2 / Vue3标注差异。Vue3 本身性能更好Proxy响应式、虚拟DOM重写、diff优化但不合理写法依然会卡顿。一、响应式数据优化Vue核心开销1. 避免不必要响应式大列表、第三方实例、不需要监听的数据不要放入响应式。Vue2Object.freezeVue3markRaw标记对象不做响应式shallowRef / shallowReactive浅层响应script setup import { markRaw, shallowRef } from vue // ✅ markRaw复杂大对象完全不做响应式 const bigObj markRaw({ list: new Array(10000).fill(1) }) // ✅ shallowRef只监听 .value内部属性不响应 const shallowData shallowRef({ name: test, bigList: [] }) shallowData.value { name: new } // 触发更新 shallowData.value.name xxx // ❗不会触发更新 /script场景后端返回超大列表、地图实例、three.js对象不要直接丢reactive。2. 合理拆分数据避免大对象整体响应不要把所有状态塞到一个reactive大对象拆分细粒度。二、渲染与计算优化computed/watch优先computed做派生计算缓存避免模板写复杂表达式模板中不要写复杂逻辑每次渲染都会执行。❌ 不推荐template div{{ list.filter(ii10).length }}/div /template✅ 推荐template div{{ filterCount }}/div /template script setup import { computed } from vue const list ref([1,2,3,11,20]) const filterCount computed((){ return list.value.filter(ii10).length }) /scriptwatch 优化避免深度监听大对象watch(obj, fn, {deep:true})开销很大优先监听具体字段不需要监听及时销毁watch返回停止函数conststopWatchwatch(()userInfo.value.name,// 只监听name不监听整个对象(val){console.log(val)})// 组件销毁会自动停止手动停止 stopWatch()三、列表渲染优化v‑for必须绑定正确 key不要用 index 当key数组频繁增删时性能灾难key最好用业务唯一id仅静态不改动简单列表才可以用index。❌ 错误div v-for(item, index) in list :keyindex{{ item.name }}/div✅ 正确div v-foritem in list :keyitem.id{{ item.name }}/divv‑for 和 v‑if 不要放同一标签v‑for优先级高于v‑if会循环全部再判断浪费性能。❌ 坏div v-foritem in list v-ifitem.show :keyitem.id{{item.name}}/div✅ 方案1计算属性提前过滤constshowListcomputed(()list.value.filter(itemitem.show))div v-foritem in showList :keyitem.id{{item.name}}/div✅ 方案2外层套template超长大列表 → 使用虚拟列表只渲染可视区域DOM上万条数据禁止直接v‑for渲染全部DOM。库vue-virtual-scroller(vue2)vue3-virtual-scroller/vueuse/components!-- vue3-virtual-scroller示例 -- RecycleScroller classscroller :itemsbigList :item-size60 key-fieldid template #default{ item } div{{ item.name }}/div /template /RecycleScroller四、组件优化v‑once、memo(Vue3)、keep‑alive1. v‑once静态内容只渲染一次不再更新静态展示文本不需要响应更新。span v-once静态标题不会重新渲染/span2. Vue3Memo缓存组件props不变跳过渲染Memo :props[user.name] HeavyComponent :useruser / /Memo3. keep‑alive缓存组件实例避免重复创建销毁页面切换不销毁组件减少组件mount开销。router-view v-slot{ Component } keep-alive includeHome,List component :isComponent / /keep-alive /router-view注意使用keep‑alive要在onActivated/onDeactivated做逻辑不要依赖onMounted记得清理定时器、事件监听防止内存泄漏。4. 组件拆分粒度大组件拆小组件局部组件更新不会整个大组件重渲染。五、避免不必要组件重渲染Vue更新父组件更新默认所有子组件都会执行render即使props没变。Vue2Vue.memo没有使用shouldComponentUpdate等价Vue.PureComponentVue3 setup使用definePropsprops会自动浅层对比复杂对象props内部子组件使用computed派生使用Memo缓存传递函数、对象给子组件避免模板内直接创建对象/函数。❌ 模板内每次渲染生成新对象子组件认为props变化反复重渲染Child :config{a:1,b:2} change()handle()/✅ 优化把对象、函数提到script中引用稳定script setup const config {a:1,b:2} const handle (){} /script Child :configconfig changehandle/六、事件与DOM优化防抖节流高频事件scroll、resize、inputscript setup import { debounce } from lodash-es // 防抖500ms执行一次 const handleSearch debounce((val){ console.log(搜索, val) }, 500) /script input inputhandleSearch /事件委托避免大量循环绑定事件组件销毁时清除定时器、监听、事件防止内存泄漏import{onUnmounted}fromvuelettimernulltimersetInterval((){},1000)onUnmounted((){clearInterval(timer)})避免在模板中频繁操作ref dom不要频繁获取offset系列属性防止强制同步布局。七、懒加载 分包1. 路由懒加载拆分chunk不一次性加载所有页面// router/index.jsconstroutes[{path:/list,name:List,component:()import(/* webpackChunkName: list *//views/list.vue)}]2. 组件动态导入非首屏组件懒加载script setup import { defineAsyncComponent } from vue // 大弹窗组件用到才加载 const BigDialog defineAsyncComponent(()import(/components/BigDialog.vue)) /script template BigDialog v-ifshowDialog/ /template八、Vue工程构建优化vite/webpackVitebuild.rollupOptions手动分包拆分大第三方库// vite.config.jsexportdefaultdefineConfig({build:{rollupOptions:{output:{manualChunks:{vue-vendor:[vue,vue-router,pinia],element-plus:[element-plus]}}}}})按需引入UI库避免全量引入使用unplugin‑vue‑components自动按需导入。Webpack(Vue2)开启tree‑shakingexternals把大库排除打包CDN引入// webpack.configmodule.exports{externals:{vue:Vue,element-ui:ELEMENT}}九、Pinia/Vuex优化store不要存放大量UI列表数据大数据放组件本地避免store大对象拆分模块组件不要直接使用store.state复杂计算组件内用computed缓存。// ❌ template直接写 $store.state.list.filter(...)// ✅ 组件内部computedconstfilterListcomputed(()$store.state.list.filter(ii.flag))十、其他Vue特有坑Vue2不要直接给对象新增属性要用$set避免整个对象替换Vue3 ref vs reactive简单基础类型优先ref对象用reactive不要在v‑for内部使用v‑if大数据表格必须虚拟滚动不依赖原生v‑for第三方组件库的大组件优先异步导入。快速面试记忆版响应式优化markRaw/shallowRef减少不必要响应不监听大对象。渲染优化computed缓存模板不写复杂逻辑v‑for正确key不和v‑if同层长列表用虚拟列表。组件渲染v‑once、Memo、keep‑alive缓存props传递稳定引用避免子组件无效重渲染。资源加载路由组件异步懒加载defineAsyncComponent。事件内存防抖节流onUnmounted清除定时器、监听防止内存泄漏。工程构建分包、按需引入UI库、externals。