vue知识点: v-if和v-for为何不能同时使用?

在vue2和vue3的官方文档里都写到不推荐 v-if和v-for同时使用,如下代码所示:

javascript 复制代码
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo.text }}
</li>

一、vue3文档:列表渲染 | Vue.js

在vue3中,是因为当它们同时存在于一个节点上时,v-if 比 v-for 的优先级更高。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名。 v-if里是无法访问到todo的,这将会报错。

二、vue2文档:列表渲染 --- Vue.js

在vue2中,v-for 的优先级比 v-if 更高,也就是说在v-if中可以访问到v-for作用域内定义的变量别名 ,因此不会跟vue3一样报错,但并不推荐这么做,原因如下:

  1. 性能问题 :将 v-for 和 v-if 放在同一个元素上会导致性能下降。Vue 必须为每一个在 v-for 中的项目都检查 v-if 的条件,这会增加不必要的计算量。特别是当 todos 数组很大时,这种性能问题会更加明显。详见文章末尾的附录。
  2. 逻辑可读性 :从逻辑和可读性的角度来看,将过滤逻辑(v-if)和渲染逻辑(v-for)混合在一起可能会导致代码难以理解和维护。最好是先过滤数据,然后再进行渲染。

推荐写法:

写法一、先过滤数据,再使用v-for

javascript 复制代码
<template>
  <ul>
    <li v-for="todo in filteredTodos" :key="todo.id">
      {{ todo.text }}
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      todos: [
        { id: 1, text: 'Learn Vue', isComplete: false },
        { id: 2, text: 'Build something awesome', isComplete: true },
        // ... more todos
      ]
    }
  },
  computed: {
    // 得到过滤后的数据
    filteredTodos() {
      return this.todos.filter(todo => !todo.isComplete);
    }
  }
}
</script>

写法 二:利用<template>元素,将 v-if 放在 v-for 的子元素中,而不是与 v-for 直接放在同一个元素上。(在vue2中,不推荐使用,逻辑可读性虽然没问题,但数据多时,还是可能存在性能问题;在 Vue 3 中,编译器能够识别 v-for 在 v-if 的子元素上的使用情况,并进行优化,以避免不必要的虚拟 DOM 节点的创建,可以使用该写法)

javascript 复制代码
<template>
  <ul>
    <template v-for="todo in todos" :key="todo.id">
      <li v-if="!todo.isComplete">
        {{ todo.text}}
      </li>
    </template>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      todos: [
        { id: 1, text: 'Learn Vue', isComplete: false },
        { id: 2, text: 'Build something awesome', isComplete: true },
        // ... more todos
      ]
    }
  }
}
</script>

附录:

在 Vue 2 中,当你同时在一个元素上使用 v-for 和 v-if,Vue 的渲染逻辑实际上是这样的:

  1. v-for 优先于 v-if :首先,v-for 会为 todos 数组中的每个项目创建 DOM 节点。这意味着,它会为数组中的每个 todo 项目都创建一个 <li> 元素。

  2. v-if 随后应用 :然后,Vue 会检查每个由 v-for 创建的 <li> 元素上的 v-if 条件。如果 v-if 的条件不满足(即 todo.isComplete 为 true),则该节点不会被渲染到 DOM 中。但是,这并不意味着节点被销毁,而是它们只是简单地不被添加到 DOM 树中。

  3. 节点的销毁与复用 :如果 todos 数组发生变化(例如,项目被添加、删除或更改),Vue 会重新计算 v-for 和 v-if 的结果,并相应地更新 DOM。这意味着,即使 v-if 条件不满足,由 v-for 创建的节点可能仍然存在在 Vue 的虚拟 DOM 中,只是它们不会出现在实际的 DOM 树中。这些节点可以被 Vue 复用,如果它们在未来再次满足 v-if 的条件。

  4. 性能影响 :即使某些节点因为 v-if 条件不满足而不会被渲染到 DOM 中,它们仍然会被 Vue 创建和追踪,这可能会对性能产生影响,尤其是当 todos 数组很大时。

  5. 最佳实践 :为了获得最佳性能,你应该避免在同一元素上同时使用 v-for 和 v-if。如果可能,应该使用计算属性或方法来预先过滤数据,然后只对过滤后的结果进行 v-for 渲染。这样做可以减少不必要的节点创建和销毁,提高应用程序的性能。

因此,对于你给出的代码示例,即使 todo.isComplete 为 true,由 v-for 创建的 <li> 节点仍然会被 Vue 创建和追踪,只是它们不会出现在最终的渲染结果中。为了优化性能,你应该将过滤逻辑移至计算属性或方法中,并在 v-for 中仅渲染过滤后的数据。

相关推荐
IT_陈寒15 分钟前
SpringBoot实战技巧总结
前端·人工智能·后端
TeamDev19 分钟前
使用 JxBrowser 在桌面应用中集成 Spring
java·前端·后端·spring·混合应用·jxbrowser·浏览器控件
陈随易2 小时前
Rolldown 把插件改动回传提速 26 倍
前端·后端·程序员
笃行3509 小时前
集中式与分布式,KingbaseES 的四种形态共用一套内核
前端
陈随易10 小时前
Vue 编译器换掉 source map,快了三四成
前端·后端·程序员
ZhengEnCi11 小时前
12 种高级 UI 交互效果及对应 AI 提示词:从按压回弹到底部抽屉的物理感教学
前端·css·交互设计
IT_陈寒14 小时前
Redis大key删除为什么会导致服务卡顿?我的线上事故复盘
前端·人工智能·后端
系统集成-鹰翔14 小时前
ERP图片改名后仍命中识别缓存:缓存键、十分钟到期与调用计数
javascript·经验分享·后端
用户27050777252415 小时前
MCP 最小 Server 实测:3 个 JSON-RPC 报错与修法
前端
用户4993350250715 小时前
一人VIP账号多人共用:Web 代理里的会话共享怎么实现
前端