精读 Vue 官方文档系列 ?
v-for 迭代数组
v-for
可以将一个数组渲染成对应的一组列表。
使用格式如下:
v-for="(item, index) in items"
v-for="(item, item) of items"
复制代码
- items 是原数组
- item 当前迭代的元素
- index 当前迭代元素的索引
v-for 迭代对象
v-for
可以像迭代数组一样来迭代对象,差异只在于参数所表示的含义与保存的内容有所不同。
<li v-for="(value, key, index) in Objects">
{{index}} - {{key}} - {{value}}
</li>
复制代码
- value 所迭代对象中当前属性 (property) 的值(键值)。
- key 所迭代对象中当前属性 (property) 的名(键名)。
- index 当前属性 (property) 所在对象内部的索引。
由于遍历对象时,会按
Object.keys()
进行遍历,所以不能保证它的结果顺序在所有 JavaScript 引擎中都一致。
状态维护
使用 v-for
渲染列表时、它默认使用”就地更新“策略。如果数据源发生变更,例如排序,Vue 并不会移动对应 DOM 元素的顺序来匹配数据项的顺序,而是就地更新(重新渲染)每个元素。
因此采用“就地更新“策略,不适用于依赖子组件状态或临时 DOM 状态(例如:表单输入值)等列表输出。
例如通过循环生成的表单输入控件列表,实际上在数据源发生变更时、DOM 已经重新渲染,不在是之前的那个控件对象,因此对于 DOM 渲染后附加的数据
dataset
或者是绑定的事件都会被重置,这就是为什么在采用就地更新的策略下不能依赖子组件或元素的状态。
如果想提高性能,可以通过给 Vue 一个提示,以便他能追踪每个节点的身份,从而重用和重新排列现有 DOM 元素,为此,你需要为列表中的每项提供一个唯一的 key
。
并不是说开启了
key
就总是启用状态维护,Vue 还是会判断参与渲染的全部数据是否存在变更,如果参与渲染的数据全部没有发生改变才会基于key
值的存在来决定是否不启用“就地更新策略”而直接复用上次创建的 DOM 对象。
<div v-for="item in items" :key="item.id">
{{item.id}} - {{item.name}} - {{item.desc}}
</div>
复制代码
如果参与渲染的 item.desc
的值发生了变更,那么不论 item.id
有没有改变,则都会采用就地更新策略。
数组更新检测
变更方法。
变更方法指的是那些对数组本身进行操作并能够改变数组本身值的方法。
Vue 通过对 push()、pop()、unshift()、shift()、splice()、sort()、reverse()
等方法进行包装,从而能够监听数组的变更,实现响应式的视图更新。
替换方法
替换数组方法指的是基于当前操作的数组,返回一个新的数组,例如 map()、filter()、concat()、slice()
等。
对于替换数组方法,只能使用新数组来替换旧数组。
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
复制代码
注意事项
由于 JavaScript 的限制,Vue 无法检测对象新增的属性以及数组新增的索引长度和数组元素。
this.items[this.items.length-1] = 'new last';
this.itemsObj['last'] = 'new last';
this.itemsObj.oldLast = 'oldLast';
复制代码
这是因为 Vue
在初始化阶段会预先对 data
选择中的属性进行监听设置,而在初始化之后新增的属性,由于没有事先加入到 Vue 的监听序列中,所以没有被转换为响应式成员,既无法触发视图的响应式更新。解决办法之一是使用 vm.$set()
方法。
列表数据的副本
如果我们想基于原始列表数据产生一系列数据列表的副本数据(过滤、排序等),而又不会去变更原始数据,在这种情况下,我们可以通过**”计算属性“或者”方法“**来返回经过排序或筛选的副本数据。
<!--使用计算属性-->
<li v-for="item in listDataSortCopy"></li>
<!--使用方法重新计算返回-->
<li v-for="item in filterData(listData)"></li>
复制代码
由于计算属性具有缓存的特性,所以性能上的考虑应该优选计算属性。
指定重复次数
v-for
也可以接受整数,用来控制模板中的元素重复指定的次数。
<li v-for="n in 10">{{n}}<li>
复制代码
列表分组
与条件分组相同,在 <template>
元素上使用 v-for
便可以实现一个列表分组。
<table>
<template v-for="n in 10">
<tr></tr>
</template>
</table>
复制代码
v-for 与 v-if
不推荐在同一元素上使用
v-if
和v-for
。
由于 v-for
的优先级高于 v-if
所以如果将两者用在同一个元素,那么永远都是在循环中进行条件判断。
<ul>
<li v-for="item in items" v-if="item.show"></li>
<ul>
复制代码
上面的示例代码,不论当前数据项是否需要可见,v-for
总会循环固定的次数,并且每次循环还会再进行条件判断。
优化的方式有两种:
- 基于特定的需求场景,是否可以将
v-if
提取到v-for
的上一层? - 总是在循环之前,通过计算属性或者是方法对数据进行过滤,只保留符合条件的数据项,避免
v-for
与v-if
一同使用 。