前言
在上一篇文章中,详细讲过了vue的条件渲染,今天我们继续深入了解一下vue的列表循环渲染。大家在之前的例子中也有用过,下面我们就详细的讲解一下。
回顾
<script> const app = Vue.createApp({ data(){ return { listArray: ['dell', 'lee', 'teacher'] } }, template: ` <div> <div v-for="item in listArray"> {{item}} </div> </div> ` }); const vm = app.mount('#root'); </script> 复制代码
在第一章的文章中,我们写过一个todoList的例子,知道了v-for指令可以在vue模板中做循环操作,在循环过程中,我们获取到listArray之后,将listArray中的每一项都赋给item,然后将item渲染出来,就可以在浏览器中看到循环之后的内容了。
template: ` <div> <div v-for="(item, index) in listArray"> {{item}} - {{index}} </div> </div> ` 复制代码
在之前的内容中,我们还知道可以在循环的时候加上index作为数组循环的下标,下标是从 0 开始的,然后将index也在模板上输出出来,就可以在页面上看到item对应的下标了。
对象循环
之前我们看到的例子只是循环数组,那如果想要获取到对象中的每一项该怎么循环输出呢?
<script> const app = Vue.createApp({ data(){ return { listObject: { firstName: 'dell', lastName: 'lee', job: 'teacher' } } }, template: ` <div> <div v-for="(value, key, index) in listObject"> {{value}} - {{key}} - {{index}} </div> </div> ` }); const vm = app.mount('#root'); </script> 复制代码
在template中可以看到,循环的是对象时,可以指定返回三个值:value、key、index,顺序可不能乱哦。当然也可以直接输出value的,后面的两个值非必填项哦~
优化循环性能 - key
<script> const app = Vue.createApp({ data(){ return { listArray: ['dell', 'lee', 'teacher'] } }, methods: { handleAddBtnClick(){ this.listArray.push('hello') } }, template: ` <div> <div v-for="(item, index) in listArray"> {{item}} - {{index}} </div> <button v-on:click='handleAddBtnClick'>添加</button> </div> ` }); const vm = app.mount('#root'); </script> 复制代码
- 当我们点击添加按钮时,会在数组后面添加一个数据,然后将页面重新渲染,但是重新渲染整个页面对于浏览器来说是比较浪费性能的,因为每次都要将已经渲染过的数据再渲染一遍。
这时候,我们就可以给循环上添加key作为唯一值,让循环渲染出来的数据都可以通过这个key来判断是否需要重新渲染。
template: ` <div> <div v-for="(item, index) in listArray" :key="index"> {{item}} - {{index}} </div> <button v-on:click='handleAddBtnClick'>添加</button> </div> ` 复制代码
- 此时看到的效果其实和没有加
key看上去是一样的,但是当数据量大了之后,vue底层代码会通过判断key,然后看看之前有没有渲染过这个DOM元素,如果已经有了,就可以复用,不需要重新渲染了。
- 在做循环的时候,一定要在循环的DOM元素上加上
key,且这个key的值必须是唯一的。上面的例子中我们使用的是index作为key的值,但是这也有个弊端,如果插入值是在中间或者数组
- 前面添加的话,那么循环的时候还是会重新渲染所有的DOM元素。
- 在实际项目开发过程中,最好能使用后台返回的数据
id作为唯一值,或者自己确定一个不会改变的唯一值作为key。
数组变更函数
在上面的例子中,我们用到了push函数,在对数组操作的时候,还有pop、unshift、shift、splice、sort、reverse等等原生js中操作数组的函数。
handleAddBtnClick(){ this.listArray.reverse() } 复制代码
- 上面就是以
reverse函数作为例子去操作data中的数组,可以看到点击按钮的时候会直接修改数组,修改后也会重新渲染到页面上。
- 还有更多的函数,大家可以都去试一试。
替换数组
<script> const app = Vue.createApp({ data(){ return { listArray: ['dell', 'lee', 'teacher'] } }, methods: { handleAddBtnClick(){ this.listArray = ['see', 'you'] } }, template: ` <div> <div v-for="(item, index) in listArray" v-bind:key="index"> {{item}} - {{index}} </div> <button v-on:click='handleAddBtnClick'>变更</button> </div> ` }); const vm = app.mount('#root'); </script> 复制代码
之前的内容中,我们对数组进行过直接修改替换数据值,在数组也是适用这个规则的。
- 直接将
listArray数组赋新的值,即可变成一个新的数组然后重新渲染到页面上。
除了直接赋值之外,还可以用concat函数或者filter过滤掉数组内容等方式获得新的数组并重新渲染。
handleAddBtnClick(){ this.listArray = ['see', 'you'].filter(item => item === 'you'); } 复制代码
除了更新整个数组之外,还可以根据下标去更新数组中的某一个内容。
handleAddBtnClick(){ this.listArray[1] = 'Hello' } 复制代码
循环判断
在循环的时候,我们经常会对一些值进行过滤,这时候就要将之前学到的v-if指令和v-for进行结合使用了。
按照一般思维,我们会把v-if指令写在和v-for同一个DOM元素上。
template: ` <div> <div v-for="(item, index) in listArray" v-bind:key="index" v-if="item !== 'lee'"> {{item}} - {{index}} </div> </div> ` 复制代码
但是打开浏览器之后会发现好像并没有起作用,这是因为当
v-for和v-if放在同一个DOM元素上时,v-if的层级会比较高,也就是会先执行v-if,之后再执行v-for
那此时可能会想,我们可以在v-for指令执行的DOM元素里面在加一层DOM元素去执行v-if指令。
template: ` <div> <div v-for="(item, index) in listArray" v-bind:key="index"> <div v-if="item !== 'lee'"> {{item}} - {{index}} </div> </div> </div> ` 复制代码
这时候页面上已经渲染出我们想要的效果了,但是打开浏览器控制台会发现,里面的DOM元素层级好像有点多了,而且被隐藏的DOM元素外层也还有一个DOM元素包裹的。那么有没有一种写法可以只有一层DOM元素去循环判断呢?
- 答案是有的。
template: ` <div> <template v-for="(item, index) in listArray" v-bind:key="index"> <div v-if="item !== 'lee'"> {{item}} - {{index}} </div> </template> </div> ` 复制代码
- 将原来的
div改为template去做v-for的循环操作,会发现template元素也会像div一点作为一个DOM元素,但其实template只是一个占位符,并不会像div一样渲染到页面上。
总结
本章主要是把列表循环渲染详细的讲解了一遍,在文章中我们对数组的操作、变更、替换等都通过小例子试验了一遍,更多好玩的等着大家去发现哦~
看完这一章之后,大家可以回头去看看第一章中的todoList例子,可以将这两块代码进行一个融合操作,看看自己是否真的学会了。
![]UWOD(KIB9LJS9~S[T{QHM9.png ]UWOD(KIB9LJS9~S[T{QHM9.png](https://ucc.alicdn.com/pic/developer-ecology/88e07280a2cd42d1ad13e2c35feb225b.png?x-oss-process=image/resize,w_1400/format,webp)
![CIE6412X]L_CSD8_LU@TF{I.png CIE6412X]L_CSD8_LU@TF{I.png](https://ucc.alicdn.com/pic/developer-ecology/e3563ef7575048439b73a6d99e44c192.png?x-oss-process=image/resize,w_1400/format,webp)

![KFXDY~WY]TE]4O23G$BT437.png KFXDY~WY]TE]4O23G$BT437.png](https://ucc.alicdn.com/pic/developer-ecology/783adbd448294f8eaa8e98e05effdc22.png?x-oss-process=image/resize,w_1400/format,webp)







![)I)3]HUFYYFV9J)NKP_BCSF.png )I)3]HUFYYFV9J)NKP_BCSF.png](https://ucc.alicdn.com/pic/developer-ecology/3837ae63cc954c4fbc64da6d9a480202.png?x-oss-process=image/resize,w_1400/format,webp)