解決 數據與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
相關文章
相關標籤/搜索