一、数据响应式
Vue.js 一个核心思想是数据驱动。所谓数据驱动,是指视图是由数据驱动生成的,我们对视图的修改,不会直接操作 DOM,而是通过修改数据。
下图是Vue的官方文档中的图解,黄色部分是 Vue 的渲染方法,视图初始化和视图更新时都会调用render 方法进行重新渲染。渲染时不可避免地会 touch 到每个需要展示到视图上的数据(紫色部分),触发这些数据的 get 方法从而收集到本次渲染的所有依赖。而当我们在修改这些收集到依赖的数据时,会触发数据中的 set 属性方法,该方法会修改数据的值并 notify 到依赖到它的观察者,从而触发视图的重新渲染。
而我们定义在data中的数据并没有set,get的计算属性,get、set方法是如何产生的呢?这便是Vue的数据响应式的核心工作,重写数据的 get 和 set 属性方法。
二、让数据变成响应式
1、getter、setter
let obj = {
firstName: "dl",
lastName: "xx",
get name() {
return this.firstName + this.lastName;
},
set name(value){
this.firstName = value[0]
this.lastName = value.slice(1)
},
age: 18
};
obj.name = 'dlcc'
console.log( obj.name);
const Vue = window.Vue
const myData = {
n:0
}
new Vue({
data: myData,
template: `
<div>{{n}}</div>
`
}).$mount('#app')
setTimeout(() => {
myData.n += 10
}, 0)
console.log(myData)
在控制台进行打印就会发现 name属性下的getter、setter方法就和实例化vue中的data 里的值n打印出来变为了n:(...),也有getter、setter方法。
说明vue重写数据n,将其转换为getter/setter的对象属性。
2、Object.defineProperty( )方法
Vue是通过 JS 标准内置对象方法 Object.defineProperty 来设定将data中普通的属性n转化为getter、setter方法的属性n的。
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。
语法:
Object.defineProperty(obj, prop, descriptor)
参数:
obj:要在其上定义属性的对象。
prop:要定义或修改的属性的名称。
descriptor:将被定义或修改的属性描述符。
返回值: 被传递给函数的对象。
3、proxy() 代理
let myData = {
n: 0
}
let data = proxy({
data: myData
}) // 括号里是匿名对象,无法访问
function proxy({ data } /* 解构赋值 */ ) {
//for循环省略
let value = data.n
Object.defineProperty(data, 'n', {
get() {
return value
},
set(newValue) {
value = newValue
}
})
const obj = {}
Object.defineProperty(obj, 'n', {
get() {
return data.n
},
set(value) {
data.n = value
}
})
return obj // obj 就是代理
}
上面的方法对每个传入的数据新增 getter/setter,此后原始的数据就会被 getter/setter 所替代,相当于复制了原始数据,这样不管是操作let data = proxy(data); 中的 data,还是操作 myData,都会被我们的 getter/setter 所拦截。
结论:Vue会遍历传入的data对象所有属性,并使用Object.defineProperty把这些属性全部转为getter/setter,这样就生成一个新的对象全权负责数据——就是实例化的Vue对象vm。这样vm会成为data 的代理,对 data 的所有属性进行监控,当数值发生改变的时候,vue就调用render函数重新渲染视图。
三、Vue 的数据响应式
当你创建一个实例时
const vm = new Vue({data:{n: 0}})
- vue 会让 vm 成为 myData 的代理。
- vue 会对 myData 的所有属性进行监控。
1、在 data 中添加属性
对于一般的对象来说,可以在 data 中预先把所有可能用到的属性全部写出来,这样并不需要新增属性,只需要改它。 也可以通过其他方法来添加属性。 在了解以上原理后,我们来了解 Vue 提供的一个 API:
Vue.set(object, key, value)
或
this.$set(object, key, value)
2、对数组的方法
vue对数组进行了改变,给数组加了一层原型,在其中Vue修改了7个方法覆盖了之前数组原型的7个方法。调用这些Vue新定义的方法时,在这些新方法里Vue会加上对新添的元素的监听(相当于进行了set操作),把新数据也进行代理,这样vue就能重新监测到数组的变化了更新UI操作 具体的七个变更方法:
push()pop()shift()unshift()splice()sort()reverse()