![Vue.js企业开发实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/909/44509909/b_44509909.jpg)
2.3 列表渲染
2.3.1 遍历元素
当遍历一个数组或枚举一个对象进行迭代循环展示时,会用到列表渲染的指令v-for。v-for指令类似于JavaScript中的for循环,在Vue中提供了v-for指令用来循环数组。
在使用v-for指令时,可以对数组、对象、数字、字符串进行循环,获取其每个元素。在使用v-for指令时,要按照特定的for-in语法进行遍历,代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P38_26437.jpg?sign=1738888996-urtjpKxZzX3mt2foAh0bVowP6kQly7w0-0-7ee6616c16f46ce5c57cbf85cea4acc5)
在上面的示例代码中,items是源数据数组,item为每次迭代遍历的数组元素,index为元素在数组中的索引。
1.遍历数组
index.html文件代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P38_26440.jpg?sign=1738888996-3LoQwP1iGKWEIceDB37waYJOaBLBrc95-0-0edb6a4eea335a62f827046f546080e7)
在浏览器中运行的效果如图2.14所示。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P39_4996.jpg?sign=1738888996-9I0NliwHaAn6hzOa8EZrGjWQeYYx8ap8-0-02501e99ee5d397aa83a714698c20a4b)
图2.14 遍历数组效果
在v-for指令中,可以使用of替代in作为分隔符,因为它更接近JavaScript迭代器的语法,代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P39_26441.jpg?sign=1738888996-xA4uLO9GBu0gRoJZwBEKDSi5UITUcOhx-0-870bfaac492e676f650a4ee136672585)
2.遍历对象
v-for指令不仅可以遍历数组,还可以用来遍历对象,代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P39_26442.jpg?sign=1738888996-O2zeSKkoOoH54tiGnp1rBVqG5FzZUwrn-0-8e31977021c8b6e969e2ec1973e1439f)
在上面的示例代码中,使用v-for循环迭代出来的元素有两个参数,第一个参数为对象属性的值,第二个参数为对象的属性。
index.html文件代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P39_26443.jpg?sign=1738888996-nJBz4uwc5gEitim1i3f0R0UMqCnd40yv-0-3096019c7e767ec981e594e731635eb7)
在浏览器中运行的效果如图2.15所示。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P40_5102.jpg?sign=1738888996-cySzL6fyvbvbjbstmgGNv6hj5gCCbauu-0-f9d284b95fa9a02eb752a0a689ad8f47)
图2.15 v-for的遍历对象
使用v-for指令遍历对象时,迭代的元素使用第3个参数作为索引,在上面的代码中添加第3个参数,代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P40_26444.jpg?sign=1738888996-lo4LyFUhlpJAmxLYuynpWjcALIuFmMpc-0-e1d1f42a37da52f924cf6225d1c07a64)
在浏览器中运行的效果如图2.16所示。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P40_5138.jpg?sign=1738888996-bqR6dqRXO2VJuNaFvpbkAL05Eated3PE-0-3d7f4e037a5f3dc52c86520c332f9388)
图2.16 v-for的第3个参数(索引)
3.遍历整数
v-for还可以直接遍历整数,代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P40_26445.jpg?sign=1738888996-Y2cLFGFVcsqRLwRB0nOtZ6aUMlCb77Tf-0-2257513086d88caab8209c24216a27ff)
在浏览器中运行的效果如图2.17所示。
2.3.2 维护状态
当Vue正在更新使用v-for渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置被正确渲染。这类似于Vue 1. x的语句track-by="$ index"。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P41_5193.jpg?sign=1738888996-LdDLXOdKrGl66LQlIB8i2VT9bqCzJzO8-0-80888d111d5e2b05eb53ac9313dfffd8)
图2.17 v-for遍历整数
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时DOM状态(例如:表单输入值)的列表渲染输出。
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每项提供一个唯一key属性,代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P41_26446.jpg?sign=1738888996-ovtoHF1N6g5mqEDja2xnrJ2iAL9On6oy-0-9b329242997a85e0caef7c13fc4b0431)
建议尽可能在使用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文件代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P42_26456.jpg?sign=1738888996-uTSMaGMv7jCKGMBjrk6rxZTNPTLyL9Wu-0-96cb1b2862b3dbb57257c16019253bd2)
在浏览器中运行的效果如图2.18所示。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P42_5296.jpg?sign=1738888996-WSBCi3B58U9UAb1TzOlIhMzdbgkYp2kk-0-ce97b965e904c082fb85e934ee8dc181)
图2.18 push()方法的执行效果
2.替换数组
变更方法,顾名思义,会变更调用这些方法的原始数组。相比之下,也有非变更方法,例如filter()、concat()和slice()。它们不会变更原始数组,而是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组。
非变更方法如下。
(1)concat():创建当前数组的副本,然后拼接参数中的数组,返回拼接后的新数组。
(2)slice():将数组的索引作为参数,可从已有的数组中返回选定的元素,返回新数组。
(3)map():对数组的每一项运行给定函数,返回每次函数调用的结果所组成的数组。
(4)filter():对数组的每一项运行给定函数,该函数会返回值为true的项所组成的数组。
非变更方法也和JavaScript中的方法类似。
index.html文件代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P42_26457.jpg?sign=1738888996-CeSOmIOk4GIET05ZIymeDhubba7mC2ai-0-d3f66a49fef0b05e823d16838d0062c6)
在浏览器中运行的效果如图2.19所示。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P43_5377.jpg?sign=1738888996-ytHIalPOGZJuwK5WZMnrjly5a8uGoZOF-0-254378801ffb1ad8672b35c211023c29)
图2.19 filter()方法的执行效果
在上面的代码示例中,要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据(使用非变更方法),可以使用filter()方法。
2.3.4 对象变更检测注意事项
由于JavaScript的限制,Vue无法检测对象属性的添加或移除。由于Vue会在初始化实例时对属性执行getter/setter转化,所以属性必须在data对象上存在才能让Vue将它转换为响应式的,这是由Vue的双向数据绑定决定的。
index.html文件代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P43_26459.jpg?sign=1738888996-9Ly8C7uIKLO5z4yJ1D7XBCWpP4feOyL3-0-afb1072327cccf5b75a327ca7eaacabf)
在上面的示例代码中添加的age属性不是响应式的,所以在页面中不会被渲染出来,在浏览器中运行的效果如图2.20所示。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P44_5448.jpg?sign=1738888996-wsTgOV6TBS6OpsJZgMnxaVo1CWPow2gQ-0-04442615be8b144b2a8f952c1762ff1a)
图2.20 添加非响应式属性的效果
对于已经创建的实例,Vue不允许动态添加根级别的响应式属性。但是,可以使用Vue.set(object,propertyName,value)方法向嵌套对象添加响应式属性,代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P44_5460.jpg?sign=1738888996-G2c4LDTsu0SE7K16JGKMqxi1SEZhMinE-0-006f4ec9258b2e69f5a4bccca1882d21)
我们可以使用上面的示例代码,为Vue实例中的对象添加响应式属性。
index.html文件代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P44_26461.jpg?sign=1738888996-AGkKiv5LSfsFaqGLF2nx19tiBOIfcsWZ-0-9848d1620dfdd1dd9bb1ae8b032909a0)
在浏览器中运行的效果如图2.21所示。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P44_5503.jpg?sign=1738888996-OIZjCX09ioNvVLwXS3t5LiuIdIBEOPh9-0-3d22fc5cd9f43949326578a4d0661fbc)
图2.21 添加响应式属性效果
除了上面的方法,还可以使用vm. $ set实例方法添加响应式属性,它只是全局Vue.set的别名,代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P45_5526.jpg?sign=1738888996-Q0FCP94in9yh34m4pXQ5w7XmD6SaiOtX-0-b9f1d3b31a1bef721e24955b778126c7)
有时可能需要为已有对象赋值多个新属性,例如使用Object.assign()或_.extend()。但是,这样添加到对象上的新属性不会触发更新。在这种情况下,应该用原对象与要混合进去的对象的属性一起创建一个新的对象,代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P45_26462.jpg?sign=1738888996-vTajLDcoEXJkKBP1vCQJ8DyKR8xZBj0i-0-36745829dd6ee19ea90b55e4fbcd1880)
2.3.5 在<template>上使用v-for
类似于v-if,也可以利用带有v-for的<template>来循环渲染一段包含多个元素的内容。
index.html文件代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P45_26463.jpg?sign=1738888996-MejlNuA8T3WFiwE1md6Rs0Pn2bpvBo6N-0-af20d8766066bafe0eafcf2de2f0c80d)
在浏览器中运行的效果如图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文件代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P45_26464.jpg?sign=1738888996-Zm3eEwKwFIHy2gJwA3ugErd42AYQBcTY-0-150844c38194f99e6fea6cc94dfe7e40)
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P46_5682.jpg?sign=1738888996-KbIfhINRUZul1V53AGQbGAyIbFmscn99-0-866657b7fa48b068904373f6052a9488)
图2.22 DOM渲染结果
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P46_26465.jpg?sign=1738888996-neBsZ2LQngfoTxUqTh9or4EH6PrveNQO-0-01552b7e8b17f8fa97efdb224d3e4978)
在浏览器中运行的效果如图2.23所示。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P46_5724.jpg?sign=1738888996-IIwIsFUNjEJQclcbl0d9YKfQVMn54Lha-0-b020a62af54a17b350b53385f6bafcbd)
图2.23 v-for与v-if一起使用的效果
注意 不推荐在同一个元素上使用v-for和v-if,必要情况下应该替换成计算属性computed。
index.html文件代码如下:
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P47_26574.jpg?sign=1738888996-qqWaXhth0oOWMpM8HnLKVedXo0twq9Kn-0-ef2bbb21e8eab6ed4583df2a2f617416)
在浏览器中运行的效果如图2.24所示。
![](https://epubservercos.yuewen.com/85E887/23721628409520006/epubprivate/OEBPS/Images/Figure-P47_26561.jpg?sign=1738888996-FNSABoVcMOyw9ajnq0mqgPqy4I9blSgb-0-23932fdd6d4f4014e72742fd6d1469ff)
图2.24 计算属性实现效果