vue-for注意点
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="vue.js"></script> </head> <body> <div id="app"> <form> <input type="text" v-model="name"> <input type="submit" @click.prevent="add"> </form> <ul> <li v-for="(person,index) in persons"> <input type="checkbox"> <span>{{index}}--{{person.name}}</span> </li> </ul> </div> <script> let vue=new Vue({ el:"#app", data:{ name:"", persons:[{ name:"zs" },{ name:"ls" },{ name:"ww" }], }, methods:{ add() { let newPerson={name:this.name}; this.persons.push(newPerson); this.name=''; } } }); </script> </body> </html>
push.png
add() { let newPerson={name:this.name}; // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name=''; }
为什么会出现这个问题?
因为v-for是采用“就地复用”的原则提高渲染性能的
- v-for在渲染元素的时候会先查看有没有需要渲染的元素
- 如果缓存中没有渲染的元素,就会创建一个新的放到缓存中进行渲染;如果缓存中有需要渲染的元素,则不会创建新的,直接复用原来的数据
注意点:在vue中只要数据发生了变化,则会自动重新渲染,“数据驱动界面”
怎样解决这个问题?
给每一个渲染的元素加上一个key,key的取值必须为独一无二的
<li v-for="(person,index) in persons" :key="person.id">
同时创建元素时给每个persons里的对象添加一个独一无二的ID,实现代码如下:
<script> let vue=new Vue({ el:"#app", data:{ name:"", persons:[{ name:"zs",id:1 },{ name:"ls",id:2 },{ name:"ww",id:3 }], }, methods:{ add() { let lastPerson=this.persons[this.persons.length-1]; console.log(lastPerson.id); let newPerson={name:this.name,id:lastPerson.id+1}; console.log(newPerson); // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name=''; } } }); </script>
注意点:不能用index作为:key,因为index虽然是以独一无二的,但是可以是同步变化的
具有动画的添加和删除案例(列表动画)
- 引出transition-group
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="vue.js"></script> <style> *{ margin: 0; padding: 0; } .v-enter{ opacity: 0; } .v-enter-active{ transition: all 3s; } .v-enter-to{ opacity: 1; } .v-leave{ opacity: 1; } .v-leave-active{ transition: all 3s; } .v-leave-to{ opacity: 0; } </style> </head> <body> <div id="app"> <form> <input type="text" v-model="name"> <input type="submit" @click.prevent="add"> </form> <ul> <transition-group appear> <li v-for="(person,index) in persons" :key="person.id" @click.prevent="del(index)"> <input type="checkbox"> <span>{{index}}--{{person.name}}</span> </li> </transition-group> </ul> </div> <script> let vue=new Vue({ el:"#app", data:{ name:"", persons:[{ name:"zs",id:1 },{ name:"ls",id:2 },{ name:"ww",id:3 }], }, methods:{ add() { let lastPerson=this.persons[this.persons.length-1]; console.log(lastPerson.id); let newPerson={name:this.name,id:lastPerson.id+1}; console.log(newPerson); // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name=''; }, del(index){ this.persons.splice(index, 1); } } }); </script> </body> </html>
列表动画的注意点
- <transition-group>标签会自动给需要做动画的元素添加一个
<span></span>
将其包起来,但是这样是不合理的,我们可以通过在transition-group标签上添加tag属性来指定添加什么元素作为需要执行动画的父元素
我们删除原有的ul标签,给transition标签添加tag="ul"则可达到一样的效果
<!-- <ul>--> <transition-group appear tag="ul"> <li v-for="(person,index) in persons" :key="person.id" @click.prevent="del(index)"> <input type="checkbox"> <span>{{index}}--{{person.name}}</span> </li> </transition-group> <!-- </ul>-->
- 列表动画引起的key混乱
添加了tag之后新增元素就没有动画了,反而第一次添加的那个数据发生动画,这个现象叫做“动画混乱”
为什么会发生这种想现象呢?因为最后一个元素的ID一直没有变,所以新添加的元素的key都是一样的,又由于v-for“就地复用”的原则,就发生了动画混乱
解决方案,代码如下:
将最后一个元素的ID直接设置给data中的add,在执行add方法时,首先将this.id自增,然后直接将自增后的id赋值给新增的person的id,就可以解决动画混乱的问题了
<script> let vue=new Vue({ el:"#app", data:{ name:"", persons:[{ name:"zs",id:1 },{ name:"ls",id:2 },{ name:"ww",id:3 }], id:3 }, methods:{ add() { this.id++; // let lastPerson=this.persons[this.persons.length-1]; console.log(id); let newPerson={name:this.name,id:id}; console.log(newPerson); // this.persons.push(newPerson); this.persons.unshift(newPerson); this.name=''; }, del(index){ this.persons.splice(index, 1); } } }); </script>