Vue中使用v-for时key值绑定删除元素总是最后一个
Vue中使用v-for时key值绑定删除元素总是最后一个在vue中使用v-for的时候需要给每个item绑定一个唯一的值,这个值可以是number或者string类型的值。key的作用主要是用在Vue的虚拟dom算法,在新旧nodes元素对比时辨识。Vue会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。重复的key会造成渲染错误。这边演示一个删除一个元素后渲染出错的情况。看下面一
Vue中使用v-for时key值绑定删除元素总是最后一个
在vue中使用v-for的时候需要给每个item绑定一个唯一的值,这个值可以是number或者string类型的值。key的作用主要是用在Vue的虚拟dom算法,在新旧nodes元素对比时辨识。Vue会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。重复的key会造成渲染错误。这边演示一个删除一个元素后渲染出错的情况。
看下面一段代码:
<!-- 父组件 -->
<template>
<div id="app">
<children v-for="(item,index) in list" :item='item' :index='index' :key='index' @removeItem='removeItem' />
<el-button @click="addItem">添加</el-button>
</div>
</template>
<!-- 子组件 -->
<template>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="姓名">
<el-input v-model="form.name"></el-input>
<el-button class="button" @click="remove">删除</el-button>
</el-form-item>
</el-form>
</template>
// 父组件data
data(){
return{
list:[
{
name:'乔治1',
},
{
name:'乔治2',
},
{
name:'乔治3',
},
]
}
},
// 父组件methods
methods:{
// 删除元素
removeItem(i){
this.list.splice(i,1)
},
// 添加元素
addItem(){
var num = this.list.length + 1
this.list.push({name:'乔治' + num})
},
},
//下面是子组件
props:{
item:{
type:Object
},
index:{
type:Number
}
},
data(){
return{
form:{}
}
},
created() {
this.form = this.item // 注意这个赋值
},
methods: {
remove(){
this.$emit('removeItem',this.index)
}
},
页面效果如下:
点击第一个元素的删除按钮查看效果如下:
这边看到的是第三个元素被删除了,我们打印一下数组list,看看数组是否正确,可以看到,数组是正确的,但是展示的还是错的。
这边对代码进行改动,因为删除第一个元素的时候,第一个元素绑定的key值是下标0,删除第一个后,第二个的下标就会变成0,依次类推,最终缺少的下标是最后一个元素的下标。所以就把最后一个元素删除了(展示效果)。现在我们把key值绑定换一种方式。
代码如下:
<template>
<div id="app">
<!-- 父组件 -->
<children v-for="(item,index) in list" :item='item' :index='index' :key='symbol(index)' @removeItem='removeItem' />
<el-button class="add-button" @click="addItem">添加</el-button>
</div>
</template>
<!-- 把key值绑定成es6的symbol唯一值类型,把下标传进去转换为唯一值绑定成key -->
symbol(i){
return Symbol(i)
},
这边再次测试,再次删除第一个元素,查看效果,效果图如下:
可以看到删除已经成功了。
但是如果这样绑定key值,表面上是看不出什么问题的,现在我在子组件的生命周期里放一层打印,就可以看出效果
created() {
this.form = this.item
console.log('组件创建!')
},
查看效果:
可以看到,删除成功后走了剩下两个子组件的生命周期,证明剩下的组件全都重新创建了一遍,因为key值变化的原因导致,因为symbol数据类型每次都不一样,每次数组长度发生变化都会重新绑定key值,导致每次数组长度发生改变,触发v-for比较key值的操作,但是key值不一样,会重新创建组件,现在还只是一个小表单,实际开发中可能小的组件中有需要发送请求的操作,或者小组件数量较多,这种重渲染会产生性能问题,就违背了绑定key值的初衷,所以这样绑定还是不够好。如果是数组长度不变的遍历是可以使用symbol绑定key值的。现在我们把key值绑定再次换回index绑定,但是子组件需要做一些改动
代码如下:
<!-- 父组件 -->
<template>
<div id="app">
<children v-for="(item,index) in list" :item='item' :index='index' :key='index' @removeItem='removeItem' />
<el-button class="add-button" @click="addItem">添加</el-button>
</div>
</template>
<!-- 子组件 -->
<template>
<!-- 子组件表单绑定的数据依赖传递过来的item -->
<el-form ref="form" :model="item" label-width="80px">
<el-form-item label="姓名">
<el-input v-model="item.name"></el-input>
<el-button class="button" @click="remove">删除</el-button>
</el-form-item>
</el-form>
</template>
created() {
// this.form = this.item 这一行代码注释掉,数据直接依赖父组件传递的数据
console.log('组件创建!');
},
测试效果如下:
可以看到组件没有再次创建,页面渲染也没有出错。不过实际项目中可能会有不同。
在我们正常的业务场景中,这样的表单数据,或者数据都会有id属性,每一条数据都有自己的id,可以直接把key值绑定为id,如果是多表单提交的情况下,需要把表单抽成组件使用,这个时候新建表单是没有id的,我这边需求是新建表单的id传递给后端一个为0的id,这样新建的表单就会出现id相同的情况,可以使用负值的id进行绑定,提交的时候判断id是否大于0,如果小于零就把id换成0提交,不小于则直接提交,就可以直接把key绑定为id了,然后在子组件的生命周期里赋值也可以正常渲染。这个官方不建议使用index绑定key值,上面绑定却正常有效,如果有比较了解原理的大佬还望评论区指点,不胜感激!
更多推荐
所有评论(0)