出現數組不能按照索引進行跟新的原因是處於性能考慮的,但是整體數組的增加刪除是可以監聽到的;對於對象新增屬性不能監聽是因為沒有在生成vue實例時候放進watcher收集依賴。
首先我們先來了解vue數據響應的原理。官方文檔的解釋:
當你把一個普通的 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象所有的屬性,並使用 Object.defineProperty 把這些屬性全部轉為 getter/setter。
當該屬性的值為一個數組時,通過索引修改數組某一項的值或使用數組的某些方法修改數組並不能觸發set;當屬性的值為一對象時,直接修改對象中屬性的值時也無法觸發set。
為了解決當你利用索引直接設置一個數組項問題,以下兩種方式都可以實現和 vm.items[indexOfItem] = newValue
相同的效果,同時也將在響應式系統內觸發狀態更新:
// Vue.set Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue)
你也可以使用 vm.$set
實例方法,該方法是全局方法 Vue.set
的一個別名:
vm.$set(vm.items, indexOfItem, newValue)
為了解決當你修改數組的長度問題,你可以使用 splice
:
vm.items.splice(newLength)
對象變更檢測注意事項:
還是由於 JavaScript 的限制,Vue 不能檢測對象屬性的添加或刪除:
var vm = new Vue({ data: { a: 1 } }) // `vm.a` 現在是響應式的 vm.b = 2 // `vm.b` 不是響應式的
對於已經創建的實例,Vue 不允許動態添加根級別的響應式屬性。但是,可以使用 Vue.set(object, propertyName, value)
方法向嵌套對象添加響應式屬性。例如,對於:
var vm = new Vue({ data: { userProfile: { name: 'Anika' } } })
當修改對象的屬性或為對象添加屬性時,應該使用以下方法:
Vue.set(vm.userProfile, 'age', 27)
或者
vm.$set(vm.userProfile, 'age', 27)
有時你可能需要為已有對象賦值多個新屬性,比如使用 Object.assign()
或 _.extend()
。在這種情況下,你應該用兩個對象的屬性創建一個新的對象。所以,如果你想添加新的響應式屬性,不要像這樣:
Object.assign(vm.userProfile, { age: 27, favoriteColor: 'Vue Green' })
你應該這樣做:
vm.userProfile = Object.assign({}, vm.userProfile, { age: 27, favoriteColor: 'Vue Green' })
由於數據響應原理機制, Vue 不允許動態添加根級響應式屬性,所以你必須在初始化實例前聲明所有可能用到的根級響應式屬性,且為這些屬性都設一個初值,哪怕只是一個空值。
回歸正題,我項目中遇到的這個問題,解決方法:
1. 運用this.$forceUpdate()強制刷新。
2. 使用vm.$set(vm.items, indexOfItem, newValue)
eg. vm.$set(vm.dataList[i], picUrl, 'data:image/jpg;base64,' + response.data)