【Vue.js】列表渲染

149 阅读4分钟

1. 概述

v-for 指令是一个 Vue 的内置指令,可以根据特殊的数据类型来进行批量渲染。(列表渲染)

2. 基本语法

2.1. 数组遍历

语法形式:

v-for="..." -> (item, index) in/of list

代码示例:

基本使用:

<template>
  <ul class="student-list">
    <!-- 枚举数组 -->
    <li
      v-for="item of list"
      :key="item.id"
    >
      <span>{{ item.id }} :</span>
      <span> - {{ item.name }} </span>
      <span>分数: {{ item.score | scoreFilter }}</span>
    </li>
  </ul>
</template>

解构使用:

<template>
  <ul class="student-list">
    <!-- 枚举数组 -->
    <li
      v-for="{ id, name, score } of list"
      :key="id"
    >
      <span>{{ id }} :</span>
      <span> - {{ name }} </span>
      <span>分数: {{ score | scoreFilter }}</span>
    </li>
  </ul>
</template>

补充:

  1. index 为可选项
  2. in/of 都可以使用 (数组, 对象, 字符串) (语义化);数组遍历可以使用 of 作为分隔符来替代 in,这更接近 JavaScript 的迭代器语法
  3. JavaScript枚举对象或遍历的概念里面, for-in是key枚举, for-of是item的枚举 (Symbol.iterator)
  4. 可迭代对象遍历时用for-of(item, index), 遍历对象时使用for-in (value, key, index)
  5. 在Vue3中, 可以直接解构v-for的值使用
<template>
  <p v-for="{ message, id }, index) in items"></p>
</template>

官方建议

  1. v-for 建议搭配 key:key属性必须是唯一的值,方便 vue 的"就地更新策略"的实施
  2. 除非万不得已, 否则不建议使用index作为key值 (key-index对应的是数组的索引下标, 操作数组 -> 驱动渲染更新, key标识打乱, 会被重新渲染, 导致页面性能变差)

2.2. 对象遍历

语法形式

v-for="(value, prop, index) in object"

代码示例

<template>
  <!-- 对象属性枚举 -->
  <ul class="student-info">
    <h3>当前学生信息: </h3>
    <li
      class="info-item"
      v-for="(value, prop, index) in currentStudent"
      :key="prop"
      :data-index="index"
    >
      <span>property: {{ prop }}</span>
      <span>value: {{ value }}</span>
    </li>
  </ul>
</template>

补充

遍历对象的顺序会按照 Object.keys 的结果进行遍历

2.3. 数字遍历

语法形式:

v-for="item in num"

代码示例

<template>
  <ul v-for="num in 10">
    <li>{{ num }}</li>
  </ul>
</template>

2.4. 字符串遍历

语法形式:

v-for="item in str"

3. v-for & v-if 搭配使用 (不推荐)

注意

  • 优先级 (Vue2 和 Vue3 是有区别的)
  • 列表渲染和条件渲染逻辑

4. v-for的强大之处 (适用范围)

  1. 遍历数组
  2. 遍历对象
  3. 遍历字符串
  4. 遍历数字 注意: 遍历数字是从1开始的(1, 2, 3, 4, 5)

5. template 与 v-for

  • 在 Vue3 中, 当你使用 <template v-for> 时,key 应该被放置在这个 <template> 容器上:
  • Vue2 里面 key 不能绑定在template, 需要绑定在响应的元素中

6. 组件上也可以使用 v-for

  • v-for item要记得传递属性 (避免v-for与组件功能与数据耦合)
  • 保证组件有合理的配置性, 达到最好的复用效果
  • 不自动将 item 注入组件的原因是,这会使组件与 v-for 的工作方式紧密耦合。明确其数据的来源可以使组件在其他情况下重用。

7. 数组的检测机制

1. 思考:

  • 在操作 vm 实例时, 不可能每次操作数组都回去从新赋值
  • 对于不返回新数组的方法, 直接设置setter显得无能为力 ( Object.defineProperty 本身没办法侦听数组方法调用造成的引用值数据的变化 (push, pop, shift, splice, sort, reverse))

2. 监测数组

  • Vue 的解决方案: 对以上方法进行包裹和封装 ( push, pop , shift , splice, sort, reverse)
  • Vue 对原有的(push, pop, shift, splice, sort, reverse)方法进行了修饰, 使其能够在 setter 中准确监听并设置
var _arrProto = Array.prototype;

var ARR_METHODS = [
  'push',
  'unshift',
  'pop',
  'shift',
  'splice',
  'sort',
  'reverse'
];

ARR_METHODS.forEach(function (methodName) {
  Array.prototype[methodName] = function () {
    _arrProto[methodName].apply(this, arguments);
  }
});
  • 替换数组是否会重新渲染整个DOM列表 ? (性能担忧)
    • 不一定, Vue对DOM操作时, 存在将大量新旧节点进行对比的算法(diff)
    • Vue将DOM重新渲染的程度进行最小化, 做到已有的DOM节点的最大化复用

8. v-forkey 的就地更新机制

1. 就地更新

  • 当没有绑定key的时候, 操作节点时, 所有的节点都会发生变化

    • delete item-2 -> 'item-3' -> 'item-2' (查看 DOM 元素的闪烁变化)
  • 就地更新的优点: 只替换需要替换的部分, 节省渲染的程度, 就地复用不需要修改的程序

  • 是否绑定key值就地更新的对比:

    • 不绑定key值, Vue无法更新/改变用户手动输入的值或者data中无变化的值
    • 不设置(a.key === b.key -> a.subVnode === b.subVnode -> patchVnode/removeVNode)
    • 给v-for的元素绑定key值,可以根据key锁定准确的就地更新(sameVNode, patchVnode)
    • 设置了(a.key !== b.key 不执行打补丁的代码)

2. 补充:为什么待操作数组的列表不能够以 index 作为 key ?

  • 操作数组后:
    1. index发生了改变
    2. key 也会发生改变
    3. sameVnode方法无法判断key值是否为初始时绑定的key值
  • Vue 默认按照“就地更新”的策略来更新通过 v-for 渲染的元素列表。
  • 当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。
  • 默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时 DOM 状态 (例如表单输入值) 的情况。