Vue中数组更新后,页⾯没有动态刷新问题
最近使⽤vue开发时,在⼀个函数中使⽤for循环,改变了页⾯中的数组,在函数中查看是修改成功的,但是页⾯中没有动态刷新。
在Vue的官⽅⽂档有提到这样⼀个注意事项:
数组变更检测注意事项:
由于 JavaScript 的限制,Vue 不能检测以下数组的变动:
1. 当你利⽤索引直接设置⼀个数组项时,例如:vm.items[indexOfItem] = newValue
2. 当你修改数组的长度时,例如:vm.items.length = newLength
举个例⼦:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
也就是说,直接设置数组的某⼀项的值,虽然改变了数组的值,但视图上显⽰的仍为数组之前的值,数据的响应失效了。出现这种现象的根本原因是什么呢?
⾸先我们先来了解vue数据响应的原理。官⽅⽂档的解释:
当你把⼀个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使⽤ Object.defineProperty 把这些属性全部转为 getter/setter。
也就是说当改变data中属性的值时会触发其相应setter的调⽤,从⽽实现响应的操作。但getter和setter是有局限性的。我们先来看下⾯的这个例⼦:
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
vue json字符串转数组->(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
通过上述例⼦可以观察得出:
当该属性的值为⼀个数组时,通过索引修改数组某⼀项的值或使⽤数组的某些⽅法修改数组并不能触发set;当属性的值为⼀对象时,直接修改对象中属性的值时也⽆法触发set。
为了解决当你利⽤索引直接设置⼀个数组项问题,以下两种⽅式都可以实现和vm.items[indexOfItem] = newValue相同的效果,同时也将在响应式系统内触发状态更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
你也可以使⽤实例⽅法,该⽅法是全局⽅法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 (sponseCode == '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() {
}
};
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论