Vue3 v-memo 指令详解:让你的列表渲染性能翻倍 🚀

📋 概述

v-memo 是 Vue 3.2+ 新增的指令,用于缓存模板的一部分 ,只有当指定的依赖项发生变化时,才会重新渲染该部分。相比 v-ifv-memo 更加精细化控制渲染时机,可以显著提升列表渲染性能。


🔰 基本用法

语法

vue 复制代码
<template>
  <div v-memo="[依赖项1, 依赖项2, ...]">
    <!-- 内容 -->
  </div>
</template>

v-memo 接收一个数组作为参数,数组中包含需要监听的响应式依赖。只有当数组中的任意一项发生变化时,被包裹的内容才会重新渲染。

简单示例

vue 复制代码
<script setup>
import { ref } from 'vue'

const count = ref(0)
const name = ref('张三')
</script>

<template>
  <!-- 只有 name 变化时重新渲染 -->
  <div v-memo="[name]">
    <p>用户名: {{ name }}</p>
    <p>计数: {{ count }}</p>
  </div>
</template>

效果:

  • name 变化时,整个 div 会重新渲染
  • count 变化时,div 不会重新渲染(因为 count 不在依赖数组中)

🔄 v-memo vs v-if

v-if 的问题

vue 复制代码
<!-- v-if 控制整个元素的显示/隐藏 -->
<div v-if="isVisible">
  <p>姓名: {{ name }}</p>
  <p>年龄: {{ age }}</p>
  <p>城市: {{ city }}</p>
</div>

v-if="false" 会完全移除 DOM 元素,后续需要重新创建。

v-memo 的优势

vue 复制代码
<!-- v-memo 保留 DOM,仅控制是否更新 -->
<div v-memo="[name, age]">
  <p>姓名: {{ name }}</p>
  <p>年龄: {{ age }}</p>
  <p>城市: {{ city }}</p>
</div>
  • DOM 元素始终保留
  • 只有 nameage 变化时,才重新渲染内容
  • city 变化不会触发重新渲染

对比表

特性 v-if v-memo
DOM 操作 创建/销毁 DOM 保留 DOM,仅更新内容
性能开销 频繁切换时开销大 适合内容频繁变化的场景
条件变化 完全不渲染 保持渲染,仅更新数据
适用场景 条件性显示/隐藏 条件性更新内容

💡 实际应用场景

场景一:大列表渲染优化

vue 复制代码
<script setup>
import { ref } from 'vue'

const items = ref([
  { id: 1, name: '商品A', price: 100, count: 2 },
  { id: 2, name: '商品B', price: 200, count: 1 },
  { id: 3, name: '商品C', price: 300, count: 3 },
])

const isVip = ref(false)

function updateCount(id) {
  const item = items.value.find(i => i.id === id)
  if (item) item.count++
}
</script>

<template>
  <div class="cart">
    <h2>购物车</h2>
    
    <div 
      v-for="item in items" 
      :key="item.id"
      v-memo="[item.count, isVip]"
      class="item"
    >
      <span>{{ item.name }}</span>
      <span>单价: ¥{{ item.price }}</span>
      <span>数量: {{ item.count }}</span>
      <span>小计: ¥{{ item.price * item.count }}</span>
      <span v-if="isVip">VIP折扣: -¥{{ item.price * 0.1 }}</span>
      <button @click="updateCount(item.id)">+1</button>
    </div>
  </div>
</template>

优化效果:

  • 只监听 item.countisVip 的变化
  • 当其他商品变化时,当前商品不会重新渲染
  • 显著减少不必要的重渲染

场景二:表格行优化

vue 复制代码
<script setup>
import { ref } from 'vue'

const rows = ref([
  { id: 1, name: '项目A', status: '进行中', progress: 50 },
  { id: 2, name: '项目B', status: '已完成', progress: 100 },
  { id: 3, name: '项目C', status: '待开始', progress: 0 },
])

function updateProgress(id) {
  const row = rows.value.find(r => r.id === id)
  if (row) row.progress = Math.min(100, row.progress + 10)
}
</script>

<template>
  <table>
    <thead>
      <tr>
        <th>项目名</th>
        <th>状态</th>
        <th>进度</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <tr 
        v-for="row in rows" 
        :key="row.id"
        v-memo="[row.status, row.progress]"
      >
        <td>{{ row.name }}</td>
        <td>{{ row.status }}</td>
        <td>{{ row.progress }}%</td>
        <td>
          <button @click="updateProgress(row.id)">推进</button>
        </td>
      </tr>
    </tbody>
  </table>
</template>

🎯 性能优化技巧

1. 精确依赖数组

vue 复制代码
<!-- ❌ 错误:依赖过多,命中率低 -->
<div v-memo="[item.name, item.price, item.count, item.discount, ...]">

<!-- ✅ 正确:只监听真正影响渲染的依赖 -->
<div v-memo="[item.price, item.count]">
  <p>总价: ¥{{ item.price * item.count }}</p>
</div>

2. 避免不必要的 v-memo

vue 复制代码
<!-- ❌ 简单内容不需要 v-memo -->
<span v-memo="[name]">{{ name }}</span>

<!-- ✅ 复杂渲染逻辑才需要 -->
<div v-memo="[data]">
  <ExpensiveComponent :data="data" />
  <AnotherHeavyComponent />
</div>

3. 空依赖数组 = v-once

vue 复制代码
<!-- 只在组件挂载时渲染一次,后续永不更新 -->
<div v-memo="[]">
  <StaticContent />
</div>

⚠️ 注意事项

1. 与 v-for 配合

vue 复制代码
<!-- v-memo 必须在 v-for 内使用 -->
<tr 
  v-for="item in items" 
  :key="item.id"
  v-memo="[item.status]"
>
  <td>{{ item.name }}</td>
  <td>{{ item.status }}</td>
</tr>

2. 嵌套使用

vue 复制代码
<div v-memo="[outerVar]">
  <div v-memo="[innerVar]">
    <!-- 同时监听 outerVar 和 innerVar -->
    {{ outerVar }} - {{ innerVar }}
  </div>
</div>

3. 响应式依赖

vue 复制代码
<script setup>
import { ref, computed } from 'vue'

const count = ref(0)
const doubled = computed(() => count.value * 2)

// ✅ ref 和 computed 都可以作为依赖
<div v-memo="[count, doubled]">
  {{ count }} * 2 = {{ doubled }}
</div>
</script>

💡 v-memo 工作原理

内部机制

  1. 依赖追踪:记录模板中使用的响应式变量
  2. 缓存比较:将当前依赖值与上次渲染时的值进行比较
  3. 条件渲染:只有依赖变化时才执行更新

与 v-once 的区别

vue 复制代码
<!-- v-once:只渲染一次,内容永不更新 -->
<div v-once>
  {{ staticContent }}
</div>

<!-- v-memo:依赖变化时更新,不变化时跳过 -->
<div v-memo="[dynamicVar]">
  {{ dynamicVar }}
</div>

📊 性能对比

优化手段 作用层级 适用场景 性能收益
v-memo 模板级 减少不必要的重新渲染 ⭐⭐⭐⭐
computed 逻辑级 缓存计算结果 ⭐⭐⭐⭐
shallowRef 数据级 避免深层响应式开销 ⭐⭐⭐
markRaw 数据级 标记不可响应的大对象 ⭐⭐⭐
虚拟列表 DOM 级 处理超长列表 ⭐⭐⭐⭐⭐

⚡ 快速参考

vue 复制代码
<!-- 基础用法 -->
<div v-memo="[count]">{{ count }}</div>

<!-- 多个依赖 -->
<div v-memo="[name, age, status]">
  {{ name }} - {{ age }} - {{ status }}
</div>

<!-- 空数组 = 只渲染一次 -->
<div v-memo="[]">永不更新</div>

<!-- v-for 中使用 -->
<tr v-for="item in items" :key="item.id" v-memo="[item.active]">
  <td>{{ item.name }}</td>
</tr>

🎯 总结

  • v-memo:Vue 3.2+ 提供的模板级缓存指令
  • 核心功能:基于依赖变化控制是否重新渲染,而非控制显示/隐藏
  • 最佳场景:大列表渲染、复杂组件的条件更新
  • 配合使用 :与 computed虚拟列表 等配合效果更佳
  • 注意事项:避免过度使用,精确依赖数组

合理使用 v-memo 可以显著提升 Vue 应用的渲染性能,特别是在处理大型列表和频繁更新的场景中。


💬 互动时间

你在项目中有用过 v-memo 吗?有什么性能优化的心得?欢迎在评论区分享!

如果这篇文章对你有帮助,欢迎:

  • 👍 点赞
  • ❤️ 收藏
  • 👀 关注

我会持续分享 Vue 3 和前端性能优化的实战技巧~

#Vue3 #前端性能优化 #Composition API #前端开发 #Web开发

相关推荐
梨子同志1 小时前
Monorepo
前端
lihaozecq1 小时前
继 Web Coding Agent 后,我做了一个本地优先的桌面 AI Agent
前端·agent
用户298698530141 小时前
在 React 中使用 JavaScript 将 Excel 转换为 SVG
前端·javascript·react.js
CodingSpace2 小时前
ESLint
前端
Csvn2 小时前
异步错误捕获的六大陷阱:await 裹着 try-catch 就一定稳了吗?
前端
用户059540174462 小时前
向量库静默丢数据踩坑实录:Playwright 端到端测试让我排查了72小时
前端·css
星栈2 小时前
SPA 写累了?试试 LiveView:服务端管状态,前端不写 JS
前端·前端框架·elixir
labixiong2 小时前
手写Promise--微任务、静态方法、async/await 全搞懂(三)
前端·javascript
Asize2 小时前
CSS 3D:从布局到立方体
前端