問題: 在使用 vue 進行開發的過程中,可能會遇到一種情況:當生成vue實例后,再次給數據賦值時,有時候並不會自動更新到視圖上去。也就是如果在實例創建之后添加新的屬性到實例上,它不會觸發視圖更新。
vue遍歷數組對象進行渲染
<div class="hisItem" v-for="(item,index) in historyNowList" :key="item+index"> <div class="word"> <i style="color:red;">*</i> <span>{{item.option_name}}:</span> </div> <div class="hisCheck"> <el-radio v-model="item.option_value" @change="handleTestClick(item,index,item.option_value)" label="1">有</el-radio> <el-radio v-model="item.option_value" @change="handleTestClick(item,index,item.option_value)" label="0">無</el-radio> </div> </div>
使用Vue.set對數據進行一個強制更改
handleTestClick(item, key, val) { Vue.set(this.historyNowList, key, this.historyNowList[key]) }
原因: 受 ES5 的限制,Vue.js 不能檢測到對象屬性的添加或刪除。因為 Vue.js 在初始化實例時將屬性轉為 getter/setter,所以屬性必須在 data 對象上才能讓 Vue.js 轉換它,才能讓它是響應的。
所以Vue 不能檢測以下變動的數組:
當你利用索引直接設置一個項時,例如:vm.items[indexOfItem] = newValue
當你修改數組的長度時,例如:vm.items.length = newLength
例如:使用 this.arr[0] 去更新 array 的內容,視圖沒有刷新
使用 Vue.set(this.arr, 0, !this.arr[0]) 去更新 array 的內容,視圖被刷新
使用 this.arr[0] = !this.arr[0] 和 this.obj.a = !this.obj.a 同時更新,視圖被刷新
結論:
如果方法里面單純的更新數組 Array 的話,要使用 Vue.set();
如果方法里面同時有數組和對象的更新,直接操作 data 即可;
原理
每個組件實例都有相應的 watcher 實例對象,它會在組件渲染的過程中把屬性記錄為依賴,之后當依賴項的 setter 被調用時,會通知 watcher 重新計算,從而致使它關聯的組件得以更新。
受現代 JavaScript 的限制 (而且 Object.observe 也已經被廢棄),Vue 不能檢測到對象屬性的添加或刪除。由於 Vue 會在初始化實例時對屬性執行 getter/setter 轉化過程,所以屬性必須在 data 對象上存在才能讓 Vue 轉換它,這樣才能讓它是響應的。
通過 Vue.set() 改寫
Vue.set( target, propertyName/index, value )
參數: {Object | Array} target {string | number} propertyName/index {any} value
返回值:設置的值。
用法: 向響應式對象中添加一個 property,並確保這個新 property 同樣是響應式的,且觸發視圖更新。 它必須用於向響應式對象上添加新 property,因為 Vue 無法探測普通的新增 property (比如 this.myObject.newProperty = 'hi') 注意: 對象不能是 Vue 實例,或者 Vue 實例的根數據對象。
通過 $set() 改寫
vm.$set( target, propertyName/index, value )
參數: {Object | Array} target {string | number} propertyName/index {any} value
返回值:設置的值。
用法: 這是全局 Vue.set 的別名。
可以發現 Vue.set() 和 this.$set() 這兩個 api 的實現原理基本一模一樣,都是使用了set函數。 set 函數是從 …/observer/index 文件中導出的。 區別在於 Vue.set( ) 是將 set 函數綁定在 Vue 構造函數上,this.$set() 是將 set 函數綁定在 Vue原型上。