先来简化一下项目原型。就是一个列表和一个表单,点击列表的某一项,表单中显示这一项对应的数据内容,并可修改。由于发现问题的是复选框,所以表单简化为一个复选框代替。

<ul>
    <li v-for="item in list" @click="clickFn(item)">{{item.name}}</li>
<ul>
<el-form :model="curItem">
    <el-checkbox v-model="curItem.isCheck" label="选择"></el-checkbox>
</el-form>
export default{
    data(){
        list:[{
            id:1,
            name:'Keith'
        },{
            id:2,
            name:'Annie'
        }],
        curItem:{}
    },
    methods:{
        clickFn(item){
            this.curItem = item
        }
    }
}

      初始状态下,列表中的每一项都没有选中复选框的属性。点击列表中第一项,勾选复选框,再点击第二项,此时复选框应该是未勾选状态,但却依然保留第一项的勾选状态。

      第一反应考虑到是属性的响应式的问题(详情参考这里),于是将click事件优化如下:

clickFn(item){
    this.$set(this , 'curItem' , item)
}

      然而复选框依旧没有取消勾选。但无意中发现,若将element-ui中的<el-checkbox>组件改为原生复选框,勾选状态就可以正常显示了。

<input type="checkbox" v-model="curItem.isCheck" />

      为什么原生复选框状态可以正常切换,el-checkbox却不可以,是组件本身的设计缺陷吗?为了方便在项目中直接调试,我在页面中独立引入element-ui中的CheckBox组件并在源码中输出log。

import checkboxOnly from 'element-ui/packages/checkbox';
export default{
    components:{
        checkboxOnly
    }
}
<el-form :model="curItem">
    <checkboxOnly v-model="curItem.isCheck" label="选择"></checkboxOnly>
</el-form>

      以下是简化后的源码(只保留了该案例中需要的部分)及log。

data(){
    return {
        selfModel: false
    }
},
computed:{
    //v-model绑定的值
    model:{
        get(){
            console.log('get-',this.value);
            console.log('get-',this.selfModel);
            return this.value !== undefined ? this.value : this.selfModel;
        },
        set(val){
            console.log('set-',val);
            this.$emit('input',val);
            this.selfModel = val;
        }
    },
    //复选框是否被选中
    isChecked(){
        console.log(this.model);
        return this.model;
    }
}

      根据log输出可知,在切换list时,虽然数据变了,但并没有触发model的set方法,所以当首次将selfModel设置为true后,后面get方法得到的值一直是true。产生这个问题的原因是,Vue 为了尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。若要两个元素完全独立,不要复用,添加具有唯一值的 key 即可。于是通过给表单增加key的方式,强制表单重新渲染,问题就解决了。

<el-form :key="curItem.id" :model="curItem">
    <el-checkbox v-model="curItem.isCheck" label="选择"></el-checkbox>
</el-form>

 

Logo

前往低代码交流专区

更多推荐