
5.1.3 v-for
使用v-for指令可以对数组、对象进行循环,来获取到其中的每一个值。
1.v-for指令遍历数组
使用v-for指令,必须使用特定语法alias in expression,其中items是源数据数组,而item则是被迭代的数组元素的别名,具体格式如下:

下面看一个示例,使用v-for指令循环渲染一个数组。
【例5.4】v-for指令遍历数组(源代码\ch05\5.4.html)。

在浏览器中运行程序,按F12键打开控制台并切换到“Elements”选项,结果如图5-5所示。

图5-5 v-for指令遍历数组
提示
v-for指令的语法结构也可以使用of替代in作为分隔符,例如:
<li v-for="item of nameList">
在v-for指令中,可以访问所有父作用域的属性。v-for还支持一个可选的第二个参数,即当前项的索引。例如,修改上面示例,添加index参数,代码如下:

在浏览器中运行程序,结果如图5-6所示。

图5-6 v-for指令第二个参数
2.v-for指令遍历对象
遍历对象的语法和遍历数组的语法是一样的:

其中object是被迭代的对象,value是被迭代的对象属性的别名。
【例5.5】v-for指令遍历对象(源代码\ch05\5.5.html)。

在浏览器中运行程序,结果如图5-7所示。

图5-7 v-for指令遍历对象
还可以添加第二个参数,用来获取键值;获取选项的索引,可以添加第三个参数。
【例5.6】添加第二、三个参数(源代码\ch05\5.6.html)。

在浏览器中运行程序,结果如图5-8所示。

图5-8 添加第二、三个参数
3.v-for指令遍历整数
也可以使用v-for指令遍历整数。
【例5.7】v-for指令遍历整数(源代码\ch05\5.7.html)。

在浏览器中运行程序,结果如图5-9所示。

图5-9 v-for指令遍历整数
4.在<template>上使用v-for
类似于v-if,也可以利用带有v-for的<template>来循环渲染一段包含多个元素的内容。
【例5.8】在<template>上使用v-for(源代码\ch05\5.8.html)。

在浏览器中运行程序,按F12键打开控制台并切换到“Elements”选项,并没有看到<template>元素,结果如图5-10所示。

图5-10 在<template>上使用v-for
提示
template元素一般常和v-for和v-if一起结合使用,这样会使得整个HTML结构没有那么多多余的元素,整个结构会更加清晰。
5.数组更新检测
Vue将被监听的数组的变异方法进行了包裹,它们也会触发视图更新。被包裹过的方法包括push()、pop()、shift()、unshift()、splice()、sort()和reverse()。
【例5.9】数组更新检测(源代码\ch05\5.9.html)。

在浏览器中运行程序,结果如图5-11所示。按F12键打开控制台并切换到“Console”选项,在选项中输入“vm.nameList.push("1800台")”,按下Enter键,数据将添加到nameList数组中,在页面中也显示出添加的内容,如图5-12所示。

图5-11 初始化效果

图5-12 修改数据对象中的数组属性
还有一些非变异方法,例如filter()、concat()和slice()。它们不会改变原始数组,而总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组。
继续在浏览器控制台输入“vm.nameList=vm.nameList.concat(["2600台","畅销版"])”,把变更后的数组再赋值给Vue实例的nameList,按下Enter键,即可发现页面发生了变化,如图5-13所示。

图5-13 使用新数组替换原始数组
可能会认为,这将导致Vue丢弃现有DOM并重新渲染整个列表,但事实并非如此。Vue为了使得DOM元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组,这是非常高效的操作。
在Vue 3.0版本中,可以利用索引直接设置一个数组项,例如修改上面示例:

在浏览器中运行程序,结果如图5-14所示。

图5-14 通过索引向数组添加元素
从上面结果可以发现,要添加的内容已经添加到数组中了。另外还可以采用以下方法:

修改上面示例:

在浏览器中运行程序,可发现要添加的内容在页面上已经显示,结果如图5-15所示。

图5-15 使用数组原型的splice()方法
6.key属性
当Vue正在更新使用v-for渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一key属性。
下面我们先来看一下不使用key属性的一个示例。在【例5.10】中,定义一个nameList数组对象,使用v-for指令渲染到页面,同时添加三个输入框和一个添加的按钮,可以通过按钮向数组对象中添加内容。在示例中定义一个add方法,在方法中使用unshift()数组的开头添加元素。
【例5.10】不使用key属性(源代码\ch05\5.10.html)。

在浏览器中运行程序,选中列表中的第一个选项,如图5-16所示;然后在输入框中输入新的内容,单击“添加”按钮后,向数组开头添加一组新数据,页面中也相应显示,如图5-17所示。

图5-16 输入内容

图5-17 添加后效果
从上面结果可以发现,刚才选择的“洗衣机”变成了新添加的“电视机”。很显然这不是我们想要的结果。产生这种效果的原因就是v-for指令的“就地更新”的策略,只记住了数组勾选选项的索引0,当往数组添加内容的时候,虽然数组长度增加了,但是指令只记得刚开始选择的数组下标,于是就选择了新数组中下标为0的选项。
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一key属性。
修改上面示例,在v-for指令的后面添加key属性。代码如下:

此时再重复上面的操作,可以发现已经实现了想要的结果,如图5-18所示。

图5-18 使用key属性的结果
7.过滤与排序
在实际开发中,可能一个数组需要在很多地方使用,有些地方是过滤后的数据,而有些地方是重新排列的数组。这种情况下,可以使用计算属性或者方法来返回过滤或排序后的数组。
【例5.11】过滤与排序(源代码\ch05\5.11.html)。

在浏览器中运行程序,结果如图5-19所示。

图5-19 过滤与排序
8.v-for与v-if一同使用
v-for与v-if一同使用,当它们处于同一节点上时,v-for的优先级比v-if更高,这意味着v-if将分别重复运行于每个v-for循环中。当只想渲染部分列表选项时,可以使用这种组合方式。
例如【例5.12】所示,循环输出价格大于或等于5000元的商品。
【例5.12】v-for与v-if一同使用(源代码\ch05\5.12.html)。

在浏览器中运行程序,结果如图5-20所示。

图5-20 v-for与v-if一同使用