vue框架中的key详解
在之前进行列表渲染的时候,还有现在进行过渡动画的时候,我们在里面都看到了一个key
。之前给同学样去给同学样讲解key
的时候,这个东西不能重复,所以我们一般都会使用索引来进行
不推荐使用index做key
如果执行是静态渲染,则使用
index
做为key无可厚非,如果执行的是动态的渲染,则index
千万不能做为key,否则vue内部的状态机就容易出错
<body>
<div id="app">
<ul>
<li v-for="(item,index) 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:"H1001",sname:"张珊"},
{sid:"H1002",sname:"李四"},
{sid:"H1003",sname:"王五"},
]
}
})
</script>
这就是一个表态渲染,因为数组stuList
后面不会发生改变了
存在的问题
<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,index) 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: "H1001",
sname: "张珊"
},
{
sid: "H1002",
sname: "李四"
},
{
sid: "H1003",
sname: "王五"
},
]
},
methods: {
addData() {
this.stuList.unshift({
sid: this.sid,
sname: this.sname
});
this.sid = "";
this.sname = "";
}
}
})
</script>
添加数据之前
添加数据的时候
添加完成的时候
这个时候发现原本应该是“李四”这一项被钩选,结果现在变成了“张三”。原因??????
在vue的内部,vue是通过key来控制状态的,而我们在渲染的时候是通过
<li v-for="(item,index) in stuList" :key="index">
<input type="checkbox">
学号:{{item.sid}}---姓名:{{item.sname}}
</li>
我们的内部使用索引做了key ,所以在变化之前,vue记住了是key
为1 的这一项被钩选了,然后再下次重新渲染的时候,渲染完成以后,它还会将key
为1的钩选,但是这个时候,发现key已经变了
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>
我们现在再来看一下vue是怎么执行的内部对比
这个时候 vue在内部进行对比的时候,发现后面三项都没有变,只有前面多了一项,所以在渲染的时候也仅仅只会更改最前面的一项,这样效率非常高,也答会我们的数据驱动页面的本质
案例
<!DOCTYPE html>
<html lang="zh">
<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>transition中key</title>
<style>
.list-box {
list-style-type: none;
margin: 0;
padding: 0;
display: flex;
}
.list-box>li {
width: 40px;
height: 40px;
background-color: lightseagreen;
margin: 5px;
display: flex;
justify-content: center;
align-items: center;
}
.aaa-enter {
transform: translateY(-150%);
opacity: 0;
}
.aaa-enter-to,
.aaa-leave {
transform: translateY(0);
opacity: 1;
}
.aaa-leave-to {
opacity: 0;
transform: translateY(150%);
}
.aaa-enter-active,
.aaa-leave-active {
transition: all 1s linear;
}
</style>
</head>
<body>
<div id="app">
<button type="button" @click="add">+</button>
<button type="button" @click="sub">-</button>
<hr>
<transition-group name="aaa" tag="ul" class="list-box">
<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>
如果我们将上面的渲染过程里在的:key="index"
,这样就实现不了我们的效果,因为vue在内部进行对比的时候找不到你的变化项(或者会把你的变化项判断错误)
评论区