解决 数据与UI更新不一样步的坑

Bug情景再现

<template>
    <div class="store-box">
        <div v-for="(day, d) in dayList" class="checkItem-box">
            <span>{{day}}</span>
            <el-checkbox-group v-model="storeItem.arrange[d]">
                <el-checkbox :label="1">上午</el-checkbox>
                <el-checkbox :label="2">下午</el-checkbox>
                <el-checkbox :label="3">晚上</el-checkbox>
            </el-checkbox-group>
        </div>
    </div>
</template>

<script>
export default{
    data(){
        dayList: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
        storeItem: {
            arrange: []
        },
    },

    mounted(){
        const week = [
            [1,2],        //周一的选择状况
            [1],          //周二的选择状况  
            [],           //周三的选择状况
            [2,3],         //周四的选择状况
            [2,1],
            [1,2,3],
            [3]
        ]
        //为checkbox-group 赋值
        this.storeItem.arrange = week;
    }
}
</script>

获得这样的结果:javascript

clipboard.png
可是当咱们点击其它选择框的时候,没有反应html

尝试解决

最早想到的缘由应该是vue没有对arrange的改变监控到, 因而解决办法是使用 vue. setvue

this.$set(this.storeItem,   'arrange',  week)

这样修改后确实也起做用了。
⭐ 注意:这里使用 vue.set 起做用根本是,瞎猫碰上死耗子,<el-checkbox-group>不能相响应的缘由根本不是这个
并且咱们仔细读 Vue 的官方文档
Vue.set( target, key, value )
做用是向响应式对象中添加一个属性,并确保这个新属性一样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,由于 Vue 没法探测普通的新增属性 (好比 this.myObject.newProperty = 'hi')java

这里咱们根本没有添加 arrange属性,而只是去改变了arrange 属性的值,vue按理说应该是可以检测到的。后面的实验也认证了个人观点。api

实验:让咱们再把表单复杂一些。
注:部分代码已经省略数据结构

<template>
    <div v-for="(store, st) in serviceStoreList" class="store-box">
        <label>{{store.name}}</label>
        <div v-for="(day, d) in dayList" class="checkItem-box">
            <span>{{day}}</span>
            <el-checkbox-group v-model="store.arrange[d]">
                <el-checkbox :label="1">上午</el-checkbox>
                <el-checkbox :label="2">下午</el-checkbox>
                <el-checkbox :label="3">晚上</el-checkbox>
            </el-checkbox-group>
        </div>
    </div>
</template>

<script>
export default{
    data(){
        dayList: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
        serviceStoreList: [
            name: '',
            arrange: [],    
        ],
    },

    mounted(){
        const week = [
            [1,2],        //周一的选择状况
            [1],          //周二的选择状况  
            [],           //周三的选择状况
            [2,3],         //周四的选择状况
            [2,1],
            [1,2,3],
            [3]
        ]
        //为checkbox-group 赋值
        
        for (let i=0; i<3; i++){
            this.serviceStoreList[i].name = `这是  ${i} 号`;
            this.serviceStoreList[i].arrange = week;
        }
    }
}
</script>

这样写了以后, checkBox 仍是: 可以展现勾选,可是点击其它选择框没有任何反应。this

因而咱们将 mounted 里面的代码改为spa

const week = [
            [1,2],        //周一的选择状况
            [1],          //周二的选择状况  
            [],           //周三的选择状况
            [2,3],         //周四的选择状况
            [2,1],
            [1,2,3],
            [3]
        ]
        //为checkbox-group 赋值

        const  _obj = {};
        const  self  =  this;
        
        for (let i=0; i<3; i++){
               _obj = {}; 
               _obj.name = `这是  ${i} 号`;
               _obj.arrange = week;
               self.$set(self.serviceStoreList,   i,    _obj)
               // 或
               self.serviceStoreList.splice(i,  1,  _obj)
        }

仍是不会起任何做用,点击其它选择框依然是点不动,不能进行交互code

这里我反复实验了几回,发现了一个特殊的现象。就是当你去点击其它选择框的时候, vue-devtool 里面显示的数据实际上是已经改变了的。
并且,当你点击了一个checkBox, 而后去填写另外的一个表单项,好比去选择下拉,或者填写其它<el-input> 的时候,
checkBox 马上就改变了。至关于它以前的v-model 的数据实际上是正常的,只是视图卡住了。htm

最后的解决办法

vue 的数据没有问题,那么确定是 element 埋下的坑。
我的认为 <el-checkbox-group> 与 <el-check> 的数据同步有些问题。
这样写就行了

<el-checkbox-group v-model="store.arrange[d]">
         <el-checkbox :label="1"  :checked="checked"  @change="checked=!checked">上午</el-checkbox>
         <el-checkbox :label="2"  :checked="checked"  @change="checked=!checked">下午</el-checkbox>
         <el-checkbox :label="3"  :checked="checked"  @change="checked=!checked">晚上</el-checkbox>
</el-checkbox-group>

//data 里面增长一个字段
data (){
    checked:false ,           //这个 checked没有任何做用,只是为了绕开elment 的这个坑
}

这样咱们不用设置 vue.set(由于vue 其实重头到尾都可以监视到数据的改变)

const week = [
        [1,2],        //周一的选择状况
        [1],          //周二的选择状况
        [],           //周三的选择状况
        [2,3],        //周四的选择状况
        [2,1],
        [1,2,3],
        [3]
    ]
//为checkbox-group 赋值
const  _obj = {};
const  _store = [];
for (let i=0; i<3; i++){
    _obj = {};
    _obj.name = `这是  ${i} 号`;
    _obj.arrange = week;
    _store.push(_obj);
}
this.checked = false;            //需将checked 设置为false,否则选择框可能会出现所有选中的状况
this.serviceStoreList = _store;  //直接设置,checkbox也能正常交互

心得

  1. vue 只是 没法探测普通的新增属性 ,可是 Vue 可以探测到data 里面已经注册过的对象的改变,好比从新给这个对象赋值,或改变它已经注册过的属性的值(非给它新增其它属性)。不管这个对象的数据结构有多么的复杂。
  2. 少用 vue.set, 多在 <el-check> 上面显示指明 @change,让它状态改变。
  3. 再每次修改 <el-checkbox-group> 的 v-model 的值的时候,先将 checked 设置为 false
1. this.checked = false
2. this.serviceStoreList =  _store
相关文章
相关标签/搜索