Vue3中的条件渲染和列表渲染

52 阅读4分钟

条件渲染

v-if

通过v-if可以控制组件是否渲染。只会在truthy值的时候才被渲染。如:

<h1 v-if="showTitle">{{title}}</h1>

因为 v-if 是一个指令,所以必须添加到一个元素上。但是如果想同时控制多个元素呢?此时可以用<template>包裹这些元素,并在上面使用 v-if。最终的渲染时将不包含<template>。如

<template v-if="isShow">
  <h1>title</h1>
  <p>content</p>
</template>

v-else-if

可以用v-else-if搭配v-if来使用,并且可以连续使用,如:

<div v-if="type == 1">
  ...
</div>
<div v-else-if="type == 2">
  ...
</div>
<div v-else-if="type == 3">
  ...
</div>

v-else-if必须紧跟在带v-if或者v-else-if的元素之后。否则无效。

v-else

可以用v-else来配合v-if或者v-else-if使用,如:

<div v-if="type == 1">
  ...
</div>
<div v-else>
  ...
</div>

同样v-else必须紧跟在带v-if或者v-else-if的后面,否则无效。

v-show

v-showv-if用法大致一样:

<h1 v-show="showTitle">title</h1>

不同的是v-show的元素始终会被渲染并保留在 DOM 中。v-show只是简单地切换元素的 display

注意,v-show 不支持 <template> 元素,也不支持 v-else

v-if和v-show

v-if 是真正的条件渲染,因为在切换过程中,事件监听器和子组件会被销毁和重建。

v-show 则元素总是会被渲染,只是显示隐藏而已。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

v-if与v-for

当 v-if 与 v-for 一起使用时,v-if 具有比 v-for 更高的优先级。但是不推荐同时使用 v-if 和 v-for

列表渲染

v-for

我们可以用v-for基于一个数组来渲染一个列表,使用的是一个item in items的语法。如:

<div>
  <div v-for="item in students">
    {{ item.name }}
  </div>
</div>

v-for还支持一个可选的第二个参数,即当前项的索引。如:

<div>
  <div v-for="(item, index) in students">
    {{ `${index}.${item.name}` }}
  </div>
</div>

也可以用of替代in,因为它更接近js迭代器的语法:

<div v-for="item of students"></div>

类似于 v-if,你也可以利用带有 v-for 的 <template> 来循环渲染一段包含多个元素的内容。

对象

也可以用v-for来遍历一个对象。如:

<div>
  <div v-for="value in student">
    {{ value }}
  </div>
</div>

这里value就是对象每个属性的值,同样也支持第二个参数,如:

<div>
  <div v-for="(value,name) in student">
    {{ ${name}:${value}` }}
  </div>
</div>

这里就是每个属性的名称。

还支持第三个参数index,这里就不举例了。

更新和key

当我们使用v-for时,idea会提醒我们添加keykey需要是唯一的。如:

<div v-for="item in students" :key="item.id">
  ...
</div>

为什么需要添加key呢,这与更新有关。

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。

这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素。需要为每项提供一个唯一的 key attribute。

所以key的作用就是标记元素,更新时可以重用元素,提高更新时的渲染效率。

注意:不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。

数组更新检测

替换数组同样会触发更新。同时数组的以下方法也会触发更新:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

注意filter()concat() 和 slice()等方法并不改变当前数组,而是返回一个新数组,所以不触发更新,但是将新数组赋值给原数组就可以触发更新了。

过滤/排序

item in items语法中items是支持函数的,所以可以通过一个函数在不改变原数组的情况下进行过滤或排序,如

<div v-for="item in getActiveCourse" :key="item.id">
  ...
</div>

这里getActiveCourse是一个函数,因为不需要参数,所以可以直接这么写,当然也可以有参数,如

<div v-for="item in getCourse(courseType)" :key="item.id">
  ...
</div>

范围

item in items语法中items也可以是整数,这样会把模版重复对应次数,如:

<div v-for="item in 10">
  contnet
</div>

会把content重复10次。

v-if与v-for

前面我们也提到当v-ifv-for处于同一节点,v-if 的优先级比 v-for 更高,这意味着 v-if 将没有权限访问 v-for 里的变量。

解决这个问题,可以在外层加<template>,并将v-for放在<template>上即可,如:

<template v-for="item in students" :key="item.id">
  <div v-if="item.isInClass">
    ...
  </div>
</template>

在组件上使用 v-for

在自定义组件上,同样可以使用 v-for,如:

<my-component v-for="item in students" :key="item.id"></my-component>

但是item数据并不会传递到组件中,也就是说在组件中无法访问item数据,因为组件还有单独的作用域。这时候需要通过props将数据传递进去才可以,具体参考组件章节即可。