Vue 中v-for和v-if

1. v-for和v-if的渲染优先级

首先:永远不要把 v-if 和 v-for 同时用在同一个元素上。

其次:当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级,这句话代表着,当 v-if 和 v-for 同时出现。渲染函数会先执行到 v-for。我们的本意是根据用户权限来控制是否显示一个列表。但是如果代码如上的话 v-if 实际上是执行到了列表渲染的每一项。

如果遇到这种需求的话我们建议的写法是:

<div v-if = 'flag'>
    <div v-for='(item) in lcList' :key='item.id' >
</div>

如果遇到必须写一起的话建议写法:

<div v-for='(item) in lcList' :key='item.id' v-if='item.userName'>

2. Vue3 v-if的实现原理

2.1 实现原理

直接在 Vue3 Template Explore 输入一个使用 v-if 指令的栗子:

<div v-if="visible"></div>

然后,由它编译生成的 render 函数会是这样:

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_ctx.visible)
    ? (_openBlock(), _createElementBlock("div", { key: 0 }))
    : _createCommentVNode("v-if", true)
}

可以看到,一个简单的使用 v-if 指令的模版编译生成的 render 函数最终会返回一个三目运算表达式。首先,让我们先来认识一下其中几个变量和函数的意义:

  • _ctx 当前组件实例的上下文,即 this
  • _openBlock()_createBlock() 用于构造 Block TreeBlock VNode,它们主要用于靶向更新过程
  • _createCommentVNode() 创建注释节点的函数,通常用于占位

显然,如果当 visiblefalse 的时候,会在当前模版中创建一个注释节点(也可称为占位节点),反之则创建一个真实节点(即它自己)。例如当 visiblefalse 时渲染到页面上会是这样:

图片说明

在 Vue 中很多地方都运用了注释节点来作为占位节点,其目的是在不展示该元素的时候,标识其在页面中的位置,以便在 patch 的时候将该元素放回该位置。

那么,这个时候我想大家就会抛出一个疑问:当 visible 动态切换 truefalse 的这个过程(派发更新)究竟发生了什么?

派发更新时 patch,更新节点。

2.2 小结

总体来看,v-if 指令的实现较为简单,基于数据驱动的理念,当 v-if 指令对应的 valuefalse 的时候会预先创建一个注释节点在该位置,然后在 value 发生变化时,命中派发更新的逻辑,对新旧组件树进行 patch,从而完成使用 v-if 指令元素的动态显示隐藏。

图片说明