在 Vue3 中,(静态提升)是编译器层面的一种性能优化手段,其核心原理是将模板中的纯静态内容(不依赖任何动态数据、不会随状态变化的内容)提取到渲染函数之外,避免在每次组件渲染时重复创建这些内容,从而减少内存占用和重复计算,提升渲染性能。
hoistStatic
为什么需要静态提升?
在 Vue2 或未开启静态提升的情况下,组件每次重新渲染(如响应式数据变化触发更新)时,模板中的所有节点(包括完全静态的节点,如固定文本、无动态绑定的元素)都会被重新创建为虚拟 DOM 节点。
例如,一个包含大量静态文本和元素的模板,即使这些内容从未变化,每次渲染都会重复生成相同的虚拟 DOM 结构,造成不必要的性能开销。
静态提升(hoistStatic)的工作原理
Vue3 编译器在编译模板时,会分析并识别出纯静态的节点或片段(如: 这种无任何动态绑定、指令(
<div class="static">固定文本</div>/
v-if 等)、插值的内容),然后将它们“提升”到组件渲染函数(
v-for 函数)的外部,作为全局变量存储。
render
这样,无论组件重新渲染多少次,这些静态内容都只会被创建一次,后续渲染时直接复用已创建的虚拟 DOM 节点,避免重复生成。
优化效果示例
未开启静态提升时:
模板中的静态内容会被包含在渲染函数内部,每次渲染都会重新创建:
<template>
<div>
<p>静态文本1</p>
<p>静态文本2</p>
<p>{{ dynamicText }}</p> <!-- 动态内容 -->
</div>
</template>
编译后的 函数(简化):
render
function render(ctx) {
return createElementVNode('div', null, [
createElementVNode('p', null, '静态文本1'), // 每次渲染都重新创建
createElementVNode('p', null, '静态文本2'), // 每次渲染都重新创建
createTextVNode(ctx.dynamicText, 1 /* TEXT */)
])
}
开启静态提升后:
静态内容被提取到 函数外部,只创建一次:
render
// 静态内容被提升到渲染函数外,全局复用
const hoisted = [
createElementVNode('p', null, '静态文本1'),
createElementVNode('p', null, '静态文本2')
]
function render(ctx) {
return createElementVNode('div', null, [
...hoisted, // 直接复用已创建的静态节点
createTextVNode(ctx.dynamicText, 1 /* TEXT */)
])
}
可以看到,静态节点 在组件生命周期内只会初始化一次,后续渲染时直接引用,避免了重复创建的开销。
hoisted
静态提升的适用场景
纯静态元素:无任何动态绑定(/
:class/
:style 等)、无指令(
v-bind/
v-if/
v-for 等)、无插值(
v-on)的元素。
{{ }}
例:
<div class="footer">© 2023</div>
静态文本节点:不包含插值的固定文本,如 。
<p>欢迎访问</p>
静态片段:由多个静态节点组成的片段,如连续的静态元素组合。
与 PatchFlags 的协同优化
静态提升与 (静态标记)是互补的优化手段:
PatchFlags
解决“静态内容重复创建”的问题,减少渲染时的内存分配。
hoistStatic 解决“动态内容更新时全量比对”的问题,减少更新时的计算开销。
PatchFlags
两者结合,让 Vue3 在“创建”和“更新”两个阶段都能显著提升性能。
总结
的核心原理是通过编译时识别纯静态内容,将其提升到渲染函数外部复用,避免重复创建,从而减少组件渲染的性能开销。这一优化对包含大量静态内容的页面(如静态文本、固定布局元素较多的页面)效果尤为明显,是 Vue3 性能提升的重要手段之一(默认开启,无需开发者手动配置)。
hoistStatic