最近使用vue開發時,在一個函數中使用for循環,改變了頁面中的數組,在函數中查看是修改爲功的,可是頁面中沒有動態刷新。vue
在Vue的官方文檔有提到這樣一個注意事項:ajax
數組變動檢測注意事項:json
因爲 JavaScript 的限制,Vue 不能檢測如下數組的變更:api
vm.items[indexOfItem] = newValue
vm.items.length = newLength
舉個例子:數組
var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) vm.items[1] = 'x' // 不是響應性的 vm.items.length = 2 // 不是響應性的
也就是說,直接設置數組的某一項的值,雖然改變了數組的值,但視圖上顯示的仍爲數組以前的值,數據的響應失效了。出現這種現象的根本緣由是什麼呢?app
首先咱們先來了解vue數據響應的原理。官方文檔的解釋:ide
當你把一個普通的 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象全部的屬性,並使用 Object.defineProperty 把這些屬性所有轉爲 getter/setter。函數
也就是說當改變data中屬性的值時會觸發其相應setter的調用,從而實現響應的操做。但getter和setter是有侷限性的。咱們先來看下面的這個例子:ui
var person = {}; Object.defineProperties( person, { age: { defaultValue: 11, get: function () { return this.defaultValue; }, set: function (val) { this.defaultValue = val; console.log("觸發了set") } } }); // 修改屬性的值時可以觸發set person.age = 12 // 觸發了set ->觸發了set ->12 person.age ->12 // 將屬性的值設置爲一個數組,當經過索引值修改數組的某一項或使用數組的某些方法修改數組時不能觸發set person.age = [2,3,4] // 觸發了set ->觸發了set ->(3) [2, 3, 4] person.age[2] = 5 // 未觸發set ->5 person.age ->(3) [2, 3, 5] person.age.push(5) // 未觸發set ->4 person.age ->(4) [2, 3, 4, 5] // 將屬性的值設置爲一個對象,當修改對象中某屬性的值時沒法觸發set person.age = { first: 1 } ->觸發了set ->{first: 1} person.age.first = 2 // 未觸發set ->2
經過上述例子能夠觀察得出:this
當該屬性的值爲一個數組時,經過索引修改數組某一項的值或使用數組的某些方法修改數組並不能觸發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)
export default { data() { return { dataList:[], }; }, methods: { getData() { var _this = this; var dataList = []; dataList = response.data.data; for(var i=0;i<dataList.length;i++){ _this.downloadBase64(dataList[i].fielID, i, dataList); } }, downloadBase64(fielID, i, dataList) { var vm = this; $.ajax({ url: AppInter.downloadBase64, asysc: true, data: { fileName: '1.jpg', fileId: fielID }, cache: !0, timeout: 2e4, dataType: "json", type: "POST", xhrFields: { withCredentials: !0 }, crossDomain: !0, contentType: "application/x-www-form-urlencoded;charset=UTF-8", beforeSend: function () { vm.loading = weui.loading(); }, success: function (response) { if (response.responseCode == '0') { dataList[i].picUrl = 'data:image/jpg;base64,' + response.data; vm.dataList = dataList; vm.$forceUpdate(); } else { weui.alert("請求錯誤,請稍候再試", function () {}, { title: '舒適提示' }); } }, error: function (xhr, msg, err) { weui.alert("請求失敗,請稍候再試", function () {}, { title: '舒適提示' }); }, complete: function () { if (vm.loading.hide) { vm.loading.hide(); } } }) } }, created() { }, mounted() { } };