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开发

相关推荐
weixin_382395231 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__1 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.2 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~3 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华3 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子6 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅6 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni6 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学7 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端