今天在项目上要实现一个在表格里使用el-radio实现单选功能,遇到一个问题是选择不同行内的单选框时,其他行的radio状态不更新,如图:(左侧是正常效果,右侧为bug图)
查找原因,发现在script中table的:data数据变量已经更新,但视图没跟着及时渲染。
(如图,第三行的checked是没有值的,但el-radio仍是选中状态)
原理是在改变数组或对象的的某个属性时,diff算法并没有检测到数据变化,所以不会更新视图,这时需要使用JSON.parse(JSON.stringify(newArray))对数据进行一层深拷贝,即可:
<el-table-column label="位置" width="180" >
<template #default="scope">
<div v-show="scope.row.checked || scope.$index === moveIndex">
<el-radio-group
@change="handleChange(scope.row, scope.$index, scope.row.checked)"
v-model="scope.row.checked"
>
<el-radio label="-1" size="large">上</el-radio>
<el-radio label="1" size="large">下</el-radio>
</el-radio-group>
</div>
</template>
</el-table-column>
<script>
export default {
data(){
return {
data:[]
}
},
methods:{
async handleChange(row, index, checked){
let newArray = await this.data.map((item,idx)=>{
if(item == row){
item.checked = checked;
}else{
item.checked = "";
}
return item;
})
// 视图更新的关键步骤!!
this.data = JSON.parse(JSON.stringify(newArray));
}
}
}
</script>
此前,我尝试使用了this.$nextTick()方式,不生效,如果数据更新是异步进行的(例如通过API请求),确保更新数据后,使用Vue的nextTick
方法来等待DOM更新。
<script>
export default {
data(){
return {
data:[]
}
},
methods:{
handleChange(row, index, checked){
this.$nextTick(function(){
this.data.forEach((item)=>{
if(item == row){
item.checked = checked;
}else{
item.checked = ""
}
})
})
}
}
}
</script>
在网上查找类似问题,还尝试使用了this.$set()方法,这个方式看介绍是对数据进行响应式,就是解决直接改动数组并不能驱动视图更新的问题,但还是不生效,不知道怎么回事?
export default {
data(){
return {
data:[]
}
},
methods:{
handleChange(row, index, checked){
this.data.forEach((item,idx)=>{
if(item == row){
item.checked = checked;
//特意使用了$set(),还是不好使
this.$set(this.data,idx,item)
}else{
item.checked = ""
this.$set(this.data,idx,item)
}
})
}
}
}
希望能解决你遇到的同类问题,喜欢的可以点赞收藏~