Vue 3 性能优化清单:从渲染稳定性到按需加载
Vue 性能优化应分成两类:页面首次可用速度,以及更新时的渲染成本。前者主要受资源体积、请求瀑布和首屏渲染影响;后者主要受组件更新范围、数据规模和主线程任务影响。先测量再选择工具,避免把所有组件都加上缓存。
先建立可比较的基线
浏览器 Performance 面板负责定位 Long Task、组件渲染与布局成本;Network 面板检查 JS、CSS、字体和图片瀑布;Vue DevTools 的 Performance 能显示组件更新。记录至少这些指标:
- 首次内容出现和最大内容渲染时间。
- 首屏 JS 传输体积与执行时间。
- 关键交互的 INP 或实际输入延迟。
- 列表规模增加后,更新耗时如何变化。
没有基线时,“感觉快了一点”通常无法复现。
让 Props 尽量稳定
父组件每次传入新对象,会让子组件更容易更新:
<!-- 不稳定:每次渲染都创建新对象 -->
<UserRow :options="{active: user.id === activeId}" />
<!-- 稳定:直接传入真正变化的值 -->
<UserRow :active="user.id === activeId" />
列表中不要让每个子项都依赖整个全局状态。父层先算出子项需要的简单值,可以显著缩小更新范围。computed 也应返回稳定结果;如果每次都创建结构相同的新对象,下游仍可能重复执行。
控制列表和大数据的响应式成本
几千行数据即使更新很快,一次创建几千个 DOM 也会卡。优先使用分页或虚拟列表,只渲染视口附近元素。对不会深层修改的大型不可变数据,可使用 shallowRef:
const rows = shallowRef<Row[]>([])
function replaceRows(next: Row[]) {
rows.value = next
}
这要求通过替换根引用触发更新,而不是直接改内部字段。它是明确的性能取舍,不应在所有状态上默认使用。
首屏只加载当前需要的代码
路由页面使用动态导入:
const ArticleDetail = () => import('@/public/pages/articles/detail.vue')
大型编辑器、图表、PDF 和管理后台不应进入公开首页的首屏 Chunk。组件也可通过 defineAsyncComponent 按需加载。拆包后继续看请求瀑布,Chunk 太碎会增加调度与连接成本,公共依赖也可能被重复拉取。
图片和布局同样重要
- 非首屏图片设置
loading="lazy"。 - 提供稳定宽高或
aspect-ratio,避免内容跳动。 - 展示缩略图时不要下载原始 4K 图片。
- 动画优先使用
transform和opacity。 - 避免在滚动事件中同步读取并写入布局。
谨慎使用优化指令
v-once 适合永不变化的内容;v-memo 可以跳过明确条件下的子树更新;KeepAlive 适合保留昂贵页面状态。它们都会增加理解成本,只有 Profile 证明更新昂贵时才使用。
发布前检查
- 首屏是否打包了编辑器、图表等非必要依赖?
- 大列表是否分页或虚拟化?
- 子组件 Props 是否频繁创建新对象?
- 图片是否有尺寸、懒加载和合适分辨率?
- 加载骨架与真实内容尺寸是否一致?
- 优化是否在低端设备和生产构建上验证?

评论
0 条讨论