一、背景
Vue中的数据模型仅仅是普通的JavaScript对象,然而当你在修改它们的时候,视图会自动进行更新。
当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
用户是看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
每个组件里都有一个watcher 实例对象,它会在组件渲染时把属性依赖记录下来,当setter被调用时会通知 watcher 重新计算重新渲染页面。
二、检测对象数据的变化
由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
因此Vue 不能检测到对象属性的添加或删除。
Vue 不允许在已经创建的实例上动态添加新的根级响应式属性 (root-level reactive property)。
然而它可以使用 Vue.set(object, key, value)或者this.$set 实例方法将响应属性添加到嵌套的对象上。
而如果需要向一个已有对象添加多个属性,例如使用 Object.assign()创建一个新对象包含原对象属性和新的属性。
<div id="app">
<div>{{object}}</div>
<button @click='changeName'>修改对象原用属性</button>
<button @click='addAge'>额外添加对象属性(新增属性是非响应式的)</button>
<button @click='addSetColor'>额外添加对象属性(新增属性是响应式的)</button>
<button @click='addSome'>额外添加多个对象属性(新增属性是响应式的)</button>
</div>
let vm = new Vue({
el: "#app",
data: {
object:{
name:'zhaojie'
}
},
methods: {
changeName () {
this.object.name = 'madman' // 数据响应
},
addAge () {
this.object.age = 18 // 数据无响应
},
addSetColor () { // 数据响应
this.$set(this.object,'color','yellow')
//Vue.set(vm.object,'color','yellow')
},
addSome () { // 数据响应
this.object = Object.assign({}, this.object, { a: 1, b: 2 })
},
}
})
复制代码
三、检测数组数据的变化
3.1 Vue数组变异方法
Vue官方规定了 7 个数组方法,这 7 个数组方法是在保持原用功能不变的前提下添加了响应式功能,使得可以触发数组的响应式,这 7 个数组方法分别是:
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
3.2 解决Vue中无法检测的数组变动
Vue 对 data 方法返回的对象中的元素进行响应式处理时,如果元素是数组时,仅仅对数组本身进行响应式化,而不对数组内部元素进行响应式化。因此
1、当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
2、当你修改数组的长度时,例如:vm.items.length = newLength
Vue是无法检测数组的变动。
1、解决第一个问题使用以下方法可以实现与vm.items[indexOfItem] = newValue相同的效果。
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
或者
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
复制代码
2、解决第二个问题使用以下方法可以实现与vm.items.length = newLength相同的效果。
vm.items.splice(newLength)
复制代码
3.3 示例代码
<div id="app">
<div>{{array}}</div>
<button @click='changeArray'>通过索引修改数组值以及修改数组长度</button>
<button @click='useMethod(4)'>使用变异方法修改数组</button>
<button @click='changeValue(0,9)'>修改数组值并且数组能够响应的方法</button>
<button @click='changeLength(1)'>修改数组长度并且数组能够响应的方法</button>
</div>
let vm = new Vue({
el: "#app",
data: {
array : [1,2,3]
},
methods: {
changeArray () { // 数据无响应
this.array[0] = 0
this.array.length = 1
},
useMethod (value) { // 数据响应
this.array.push(value)
},
changeValue (index,value) { // 数据响应
//this.$set(this.array,index,value)
this.array.splice(index, 1, value)
},
changeLength (newLength) { // 数据响应
this.array.splice(newLength)
}
}
})
复制代码