- 响应就是当发生一些变化时,能够对于这些变化做出反应,这就是所谓响应,vue的数据响应式就是当数据发生一些变化时,Vue实例就能知道这个变化,Vue会通知到使用该数据的代码,例如,视图渲染中使用了数据,数据改变后,视图就会自动更新。
- Vue是如何知道数据发生了变化的,Vue到底做了些什么呢,看例子
let data1 = {}
Object.defineProperty(data1, 'n', {
value: 0//意思就是在data1这个对象里面的定义了一个key为n,value为0的属性
})
let data2 = {}
data2._n = 0;
Object.defineProperty(data2, 'n', {//此时的data2里面并没有n这个属性
get() { return this._n },//给对象里的'n'添加getter,用于对对象的属性的读ou添加监控
set(value) {
if (value < 0) return ////给对象里的'n'添加setter,用于对对象的属性的写添加监控
this._n = value
}
})
let data3 = proxy({ data: { n: 0 } })
function proxy({ data }) {//{data}解构赋值法,ES6新语法
const obj = {}
Object.defineProperty(obj, 'n', {
get() {
return data.n
},
set(value) {
if (value < 0) return
data.n = value
}
})
return obj // obj 就是代理
}
看代码,我们知道使用函数proxy会新创建一个对象,然后将对这个{data:{n:0}}对象属性的读写将由这个新对象来代理,那么这个新对象obj就是{data:{n:0}}对象的代理。所以当出现vm=new Vue({}data:myDate),Vue做了这样几件事
- 会让vm成为myData的代理
- 会对myData的所有属性进行监控,一旦myData的属性变了,vm就知道了 主要依靠 Object.defineProperty来实现数据响应式。
- 由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。也就是说当这个数据是数组或是对象的时候,这个响应式不能生效,发明者当然会想出一些办法来回避这些限制并保证它们的响应性。
- 对于对象 Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:
var vm = new Vue({
data:{
a:1
}
})
// `vm.a` 是响应式的
vm.b = 2
// `vm.b` 是非响应式的
对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。
Vue.set(vm.data, 'b', 2),vm.b 会变成响应式的
还能使用vm.$set实例方法,这也是全局 Vue.set 方法的别名:this.$set(this.data,'b',2)
有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign() 或 _.extend()。但是,这样添加到对象上的新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。
- 数组 假设传入一个数组的时候,后续对这个数组操作,使得数组有一些变化比如增减元素,刚开始我们就没有办法把数组中的key都声明出来,自然后面变化后的就不可能变成响应式数据,每次都用Vue.set的话也不是一个好的办法,Vue的作者大大是这样做的,改动js中的API,然后使得改动后的API可以帮我们完成数组变化并添加监控这一步,就不用我们在那一个个元素的操作了。