v-once 用于彻底静态内容,首次渲染后不再更新;v-memo 基于依赖数组智能跳过重渲染,适用于条件性稳定场景,二者均需避免误用导致更新失效。

v-once 和 v-memo 是 Vue 3 中专为减少不必要重渲染而设计的两个轻量级指令,用法不同、适用场景也不同,但目标一致:让 Vue 跳过它“知道不会变”的那部分更新。
用 v-once 锁定彻底静态的内容
v-once 的作用很明确:绑定的元素及其所有子节点,只在首次渲染时生成 DOM,之后无论响应式数据如何变化,这部分内容完全不动。它适合那些从始至终都不需要更新的片段。
- 比如弹窗标题、版权信息、固定说明文字、初始化后就不再变动的图标或 logo
- 再如文档类页面中的章节编号、作者署名、版本号等纯展示字段
- 注意:v-once 不接受表达式,直接写在标签上即可,例如
<h2 v-once>用户协议</h2>
用 v-memo 缓存“条件性稳定”的内容
v-memo 更灵活,它根据你提供的依赖数组决定是否跳过更新。只要数组里的值没变,对应区域就不会重新创建 VNode,也不会触发比对和 DOM 更新。
- 典型场景是列表项中部分字段长期不变,比如用户头像 URL、ID、用户名,而状态标签(如“在线/离线”)会频繁变化
- 写法是
v-memo="[row.id, row.avatar]",Vue 会记住这组值,仅当其中任一值变化时才重渲染该块 - 它不是冻结,而是“智能跳过”,比 v-once 更贴近真实业务逻辑
插槽内容里怎么用才有效?
插槽本身不会引发父组件重渲染,但父组件一更新,整个模板(含插槽内部绑定)都会重新求值。如果插槽里混着静态和动态内容,就容易连带浪费性能。
- 对插槽内真正不变的部分,加
v-once—— 比如<h3 v-once>订单详情</h3> - 对依赖某些字段但并非全局静态的部分,用
v-memo包裹并声明依赖 —— 比如<div v-memo="[order.no]">订单号:{{ order.no }}</div> - 避免把整个
<slot></slot>直接包进 v-memo,除非你能确保插槽内容整体稳定;更推荐按需拆分、局部包裹
别踩这两个常见坑
用错指令反而会让界面“卡住”或“不更新”,得小心:
- 依赖数组漏写或写错:v-memo 的数组必须完整覆盖影响该区块的所有响应式来源,少一个就可能跳过本该发生的更新
- 把 v-once 用在需要响应的地方:比如给一个按钮加了 v-once,那它的点击事件绑定、文本变化、class 切换全都会失效










