为什么Vue中数组/对象数据用某些方法的时候。数据变了,页面却没有更新?
Vue 实例的数据对象。Vue 将会递归将 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个的 key/value 对):浏览器 API 创建的原生对象,原型上的属性会被忽略。大概来说,data 应该只能是数据 - 不推荐观察拥有状态行为的对象。一旦观察过,你就无法在根数据对象上添加响应式属性。因此推荐在创建实例之前,就声明所有的根级响应式属性。
以上是Vue官方给的一句话
一. 首先我们先得知道以下几点,才能对这个问题有个很好的了解与解答.
- Vue的双向数据绑定的核心原理是Object.defineProperty(),当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter这个方法,Vue在初始化实例时就对属性执行了setter/getter转化过程
- 其实无论对于数组还是对象,在JavaScript中都是存储在堆内存中,保存的其实是一个地址指向堆内存的数据,因此无论是对数组进行非变异方法或者直接给对象进行添加或删除属性时,堆内存对地址指向并未改变
结合以上两点就很好理解了,总结:
- 因为有Object.defineProperty(),在初始化实例对时候,会对属性数据进行setter/getter的转化过程,所以一开始的数据才是响应式的
- 因为刚刚说了堆内存的问题,指向地址的指针并未改变,所以这些操作也并没有修改原来的实例,后面如果对数组进行某些非变异方或给对象进行添加/删除属性,Vue是没有办法对后来操作的数据进行settet/getter转化的(数据劫持),这就是所谓的JavaScript的限制。就连setter方法都没有,从而也就不会触发其它包括页面试图的更新
解决办法
(1) 数组更新检测
由于javascript的限制,Vue 不能检测以下变动的数组
- 你想利用索引直接设置某一项时,例如:vm.arr[index] = newValue
- 当你想直接设置数组的length时,例如:vm.arr.length = newLength
解决第一类问题使用以下方法
Vue.set(要修改的数组,修改哪个下标,修改成什么样)
//此时示范案例的实例采用的是vm,=> var vm = new Vue()
vm.$set(要修改的数组,修改哪个下标,修改成什么样)
//Vue.set与vm.$set功能等价
vm.arr.splice(index,1,newValue)
解决第二类问题使用以下方法
vm.arr.splice(newLength)
(2).对象更新检测
由于javascript的限制,Vue 不能检测对象属性的添加/删除
如:
var vm = new Vue({
data:{
obj:{
name:'name'
}
}
})
//此时vm.obj.name是响应式的
//如果直接对此对象进行添加属性操作
vm.obj.age = 1 //此时页面是没有数据更新的,并不是响应式
解决方法:
Vue.set(要修改的对象,键,值)
//此时示范案例的实例采用的是vm, => var vm = new Vue()
vm.$set(要修改的对象,键,值)