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>
补充:
- index 为可选项
- in/of 都可以使用 (数组, 对象, 字符串) (语义化);数组遍历可以使用 of 作为分隔符来替代 in,这更接近 JavaScript 的迭代器语法
- JavaScript枚举对象或遍历的概念里面, for-in是key枚举, for-of是item的枚举 (Symbol.iterator)
- 可迭代对象遍历时用for-of(item, index), 遍历对象时使用for-in (value, key, index)
- 在Vue3中, 可以直接解构v-for的值使用
<template>
<p v-for="{ message, id }, index) in items"></p>
</template>
官方建议
- v-for 建议搭配 key:key属性必须是唯一的值,方便 vue 的"就地更新策略"的实施
- 除非万不得已, 否则不建议使用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开始的(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-for 中 key 的就地更新机制
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 ?
- 操作数组后:
- index发生了改变
- key 也会发生改变
- sameVnode方法无法判断key值是否为初始时绑定的key值
- Vue 默认按照“就地更新”的策略来更新通过 v-for 渲染的元素列表。
- 当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。
- 默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时 DOM 状态 (例如表单输入值) 的情况。