vue框架中的key详解
之前我们在左列表渲染的时候,包括现在我们做的过渡动画,我们都看到了一个key,之前给大家讲key的时候说过key的值不能重复,所以我们一直在做索引作为key的值
不推荐使用index的值作为key的值
如果执行的时静态渲染,则使用index作为key其实也还好,但是如果执行的是动态渲染,则index千万不能作为key的值使用,否则vue内部的状态机制容易出错
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,inde) in stuList" :key="index">
学号:{{item.sid}} ------ 姓名:{{item.sname}}
</li>
</ul>
</div>
</body>
<script src="js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
stuList:[
{sid:"001",sname:"zhangsan"},
{sid:"002",sname:"lisi"},
{sid:"003",sname:"wangwu"}
]
}
})
</script>
</html>
这就是一个静态渲染,因为stuList数组在后面的操作种不会发生变化
存在的问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
学号:<input type="text" v-model="sid">
姓名:<input type="text" v-model="sname">
<button type="button" @click="addData">添加</button>
<ul>
<li v-for="(item,inde) in stuList" :key="index">
<input type="checkbox" >
学号:{{item.sid}} ------ 姓名:{{item.sname}}
</li>
</ul>
</div>
</body>
<script src="js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
sid:"",
sname:"",
stuList:[
{sid:"001",sname:"zhangsan"},
{sid:"002",sname:"lisi"},
{sid:"003",sname:"wangwu"}
]
},
methods:{
addData(){
this.stuList.unshift({
sid:this.sid,
sname:this.sname
});
this.sid = "";
this.sname = "";
}
}
})
</script>
</html>
这个时候我们会发现我们在没添加数据之前,勾选的是lisi,但是在添加数据之后勾选却变成了zhangsan
原因:
在vue的内部,vue使用key来控制状态,而我们渲染的时候不是通过key记录的状态来渲染的
<li v-for="(item,index) in stuList" :key="index">
<input type="checkbox" >
学号:{{item.sid}} ------ 姓名:{{item.sname}}
</li>
我们的内部状态使用索引作为key,所以在变化之前,vue记住key为1的这一项是勾选的,然后下次再重新渲染的时候,vue记住的状态是索引值1,所以渲染出来的结果也就是勾选的key值为1的哪一项,但是实际渲染index对应的数据已经改变了
vue在执行内部渲染的时候,执行是一个叫做diff算法,它把渲染之前和渲染之后的数据进行比较,然后只更新差异项
vue内部在执行渲染之前的数据与渲染之后做比较,这个时候对比的是key
它在执行对比的时候,发现每个key都改变了,它就又重新渲染了4个,但是本来应该就渲染1个就够了,也就是说上面的代码极大的消耗了浏览器性能,所以如果要执行的是动态渲染,我们不推荐使用index作为key
解决方案
<li v-for="(item,index) in stuList" :key="item.sid">
<input type="checkbox" >
学号:{{item.sid}} ------ 姓名:{{item.sname}}
</li>
案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.list-box{
list-style:none;
margin:0;
padding:0;
display: flex;
}
.list-box>li{
width:40px;
height:40px;
background:red;
margin:5px;
display:flex;
justify-content: center;
align-items: center;
color:#fff;
}
.aaa-enter{
transform: translateY(-150%);
opacity: 0;
}
.aaa-enter-to,.aaa-leave{
transform: translateY(0);
opacity: 1;
}
.aaa-leave-to{
transform: translateY(150%);
opacity: 0;
}
.aaa-enter-active,.aaa-leave-active{
transition: all .5s linear;
}
</style>
</head>
<body>
<div id="app">
<button type="button" @click="add">+</button>
<button type="button" @click="sub">-</button>
<transition-group tag="ul" class="list-box" name="aaa">
<li v-for="(item,index) in numList" :key="item+'aaa'">{{item}}</li>
</transition-group>
</div>
</body>
<script src="js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
numList:[0,1,2,3]
},
methods:{
add(){
this.numList.push(this.numList.length);
},
sub(){
let index = parseInt(Math.random() * this.numList.length);
this.numList.splice(index,1);
}
}
})
</script>
</html>