
2.3 列表渲染
2.3.1 遍历元素
当遍历一个数组或枚举一个对象进行迭代循环展示时,会用到列表渲染的指令v-for。v-for指令类似于JavaScript中的for循环,在Vue中提供了v-for指令用来循环数组。
在使用v-for指令时,可以对数组、对象、数字、字符串进行循环,获取其每个元素。在使用v-for指令时,要按照特定的for-in语法进行遍历,代码如下:

在上面的示例代码中,items是源数据数组,item为每次迭代遍历的数组元素,index为元素在数组中的索引。
1.遍历数组
index.html文件代码如下:

在浏览器中运行的效果如图2.14所示。

图2.14 遍历数组效果
在v-for指令中,可以使用of替代in作为分隔符,因为它更接近JavaScript迭代器的语法,代码如下:

2.遍历对象
v-for指令不仅可以遍历数组,还可以用来遍历对象,代码如下:

在上面的示例代码中,使用v-for循环迭代出来的元素有两个参数,第一个参数为对象属性的值,第二个参数为对象的属性。
index.html文件代码如下:

在浏览器中运行的效果如图2.15所示。

图2.15 v-for的遍历对象
使用v-for指令遍历对象时,迭代的元素使用第3个参数作为索引,在上面的代码中添加第3个参数,代码如下:

在浏览器中运行的效果如图2.16所示。

图2.16 v-for的第3个参数(索引)
3.遍历整数
v-for还可以直接遍历整数,代码如下:

在浏览器中运行的效果如图2.17所示。
2.3.2 维护状态
当Vue正在更新使用v-for渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置被正确渲染。这类似于Vue 1. x的语句track-by="$ index"。

图2.17 v-for遍历整数
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时DOM状态(例如:表单输入值)的列表渲染输出。
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一key属性,代码如下:

建议尽可能在使用v-for时提供key属性,除非遍历输出的DOM内容非常简单,或者刻意依赖默认行为以获取性能上的提升。
注意 不要使用对象或数组之类的非基本类型值作为v-for的key,而要使用字符串或数值类型的值。
2.3.3 数组更新检测
Vue为了增强列表渲染功能,增加了一组观察数组的方法,并且可以显示一个数组的过滤或排序的副本。
1.变更方法
Vue将被侦听的数组的变更方法进行了包裹,所以它们也会触发视图更新。这些被包裹过的方法如下。
(1)push():接收任意数量的参数并逐个追加到原数组末尾,返回新数组的长度。
(2)pop():移除数组最后一项,返回被移除的元素。
(3)shift():移除数组的第一项,返回被移除的元素。
(4)unshift():在数组前追加新元素,返回新数组长度。
(5)splice():删除指定索引的元素,并且可以在该索引处添加新元素。
(6)sort():对数组进行排序,默认按字典升序排序,返回排序后的数组。
(7)reverse():用于反转数组的顺序,返回反转后的数组。
这些方法类似于JavaScript中操作数组的方法。
index.html文件代码如下:

在浏览器中运行的效果如图2.18所示。

图2.18 push()方法的执行效果
2.替换数组
变更方法,顾名思义,会变更调用这些方法的原始数组。相比之下,也有非变更方法,例如filter()、concat()和slice()。它们不会变更原始数组,而是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组。
非变更方法如下。
(1)concat():创建当前数组的副本,然后拼接参数中的数组,返回拼接后的新数组。
(2)slice():将数组的索引作为参数,可从已有的数组中返回选定的元素,返回新数组。
(3)map():对数组的每一项运行给定函数,返回每次函数调用的结果所组成的数组。
(4)filter():对数组的每一项运行给定函数,该函数会返回值为true的项所组成的数组。
非变更方法也和JavaScript中的方法类似。
index.html文件代码如下:

在浏览器中运行的效果如图2.19所示。

图2.19 filter()方法的执行效果
在上面的代码示例中,要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据(使用非变更方法),可以使用filter()方法。
2.3.4 对象变更检测注意事项
由于JavaScript的限制,Vue无法检测对象属性的添加或移除。由于Vue会在初始化实例时对属性执行getter/setter转化,所以属性必须在data对象上存在才能让Vue将它转换为响应式的,这是由Vue的双向数据绑定决定的。
index.html文件代码如下:

在上面的示例代码中添加的age属性不是响应式的,所以在页面中不会被渲染出来,在浏览器中运行的效果如图2.20所示。

图2.20 添加非响应式属性的效果
对于已经创建的实例,Vue不允许动态添加根级别的响应式属性。但是,可以使用Vue.set(object,propertyName,value)方法向嵌套对象添加响应式属性,代码如下:

我们可以使用上面的示例代码,为Vue实例中的对象添加响应式属性。
index.html文件代码如下:

在浏览器中运行的效果如图2.21所示。

图2.21 添加响应式属性效果
除了上面的方法,还可以使用vm. $ set实例方法添加响应式属性,它只是全局Vue.set的别名,代码如下:

有时可能需要为已有对象赋值多个新属性,例如使用Object.assign()或_.extend()。但是,这样添加到对象上的新属性不会触发更新。在这种情况下,应该用原对象与要混合进去的对象的属性一起创建一个新的对象,代码如下:

2.3.5 在<template>上使用v-for
类似于v-if,也可以利用带有v-for的<template>来循环渲染一段包含多个元素的内容。
index.html文件代码如下:

在浏览器中运行的效果如图2.22所示。
template中可以放执行语句,最终编译后不会被渲染成元素。一般常和v-for指令及v-if指令结合使用,这样会使整个HTML结构没有多余的元素,从而使整个结构更加清晰。
2.3.6 v-for与v-if一同使用
当它们处于同一节点,v-for的优先级比v-if更高,这意味着v-if将分别重复运行于每个v-for循环中。当只想为部分项渲染节点时,这种优先级的机制十分有用。
index.html文件代码如下:


图2.22 DOM渲染结果

在浏览器中运行的效果如图2.23所示。

图2.23 v-for与v-if一起使用的效果
注意 不推荐在同一个元素上使用v-for和v-if,必要情况下应该替换成计算属性computed。
index.html文件代码如下:

在浏览器中运行的效果如图2.24所示。

图2.24 计算属性实现效果