在使用vuex的时候,store中的state维护的数据在做某些变更操作的时候,组件内部的数据没有做出响应式更新,究其原因是因为js在操作容器的时候有些操作不是响应式的。
哪些操作不是响应式的呢?
如果写才能变为响应式呢?
一. 数组的响应式方法
Vue 将被侦听的数组的变异方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
你可以打开控制台,然后对前面例子的 items
数组尝试调用变异方法。比如 example1.items.push({ message: 'Baz' })
。
二.数组的非响应式方法
由于 JavaScript 的限制,Vue 不能检测以下数组的变动:
- 当你利用索引直接设置一个数组项时,例如:
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 // 不是响应性的
为了解决第一类问题,以下两种方式都可以实现和 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` 不是响应式的
delete data['a'] // 不是响应式的
3.1 如果你想添加属性
对于已经创建的实例,Vue 不允许动态添加根级别的响应式属性。
但是,可以使用 Vue.set(object, propertyName, value)
方法向嵌套对象添加响应式属性。
例如,对于:
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
你可以添加一个新的 age
属性到嵌套的 userProfile
对象:
Vue.set(vm.userProfile, 'age', 27)
你还可以使用 vm.$set
实例方法,它只是全局 Vue.set
的别名:
vm.$set(vm.userProfile, 'age', 27)
3.2 如果你想为已知对象赋值多个属性
有时你可能需要为已有对象赋值多个新属性,比如使用 Object.assign()
或 _.extend()
。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,不要像这样:
Object.assign(vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
你应该这样做:
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
3.3如果你想删除属性
例如,对于:
var vm = new Vue({
data: {
userProfile: {
name: 'Anika',
age:18
}
}
})
你可以删除 age
属性:
Vue.delete(vm.userProfile, 'age')
你还可以使用 vm.$delete
实例方法,它只是全局 Vue.delete
的别名:
vm.$delete(vm.userProfile, 'age')
4. 总结
当操作数组和对象的时候,因为js有些方法不是响应式的,所以vue检测不到它的变动。但是我们不得不得到我们想要的操作,就需要使用vue提供的响应式方法:例如:
Vue.set(vm.userProfile, 'age', 27)
// 它等价于
vm.$set(vm.userProfile,'age',27)
Vue.delete(vm.userProfile,"age")
// 它等价于
vm.$delete(vm.userProfile,'age')