都知道Vue2响应式原理用的是definePorperty,那到底是怎么实现的,下面就来逐步分析去实现响应式的页面更新。
首先,在创建Vue实例的时候,会用Observer将data中的对象通过definePorperty重新定义一遍。
如:
//data
data:{
msg:'hello',
num:0
}
//change
change(){
document.innerHtml=msg
}
change()//页面展示hello
msg='hello world' //数据更新页面不发生变化
//Observer
function observer(data){
for(let key in data){
let temp=data[key] //定义一个暂时变量,
Object.defineProperty(data,key,{
get:function(){
return temp
},
set:function(val){
temp=val //为什么要这样做,如果在set,get里直接设置date[key] ,就成了无限递归卡死
},
})
}
}
到这里仅仅只是对每个变量进行了重写,但是如果更新了数据,页面并不会发生改变,因为并没有重新调用change方法,所以页面的内容没有重新赋值仍是hello。如果能在每次set完之后,就去执行change函数,那就能做到页面更新,但如果多个函数依赖到此数据就麻烦了。
所以接下来,我们要收集依赖此数据的函数或变量(收集依赖),然后实现页面更新(派发更新)
如:
//data
data:{
msg:'hello',
num:0
}
//change
change(){
document.innerHtml=msg
}
window.__func=change //因为会可能有很多个页面要依赖到此数据,所以定义一个全局变量来暂时保存这个函数。
change() //change函数里先获取msg进入get函数,再设置msg进入set函数
window.__func=null //当依赖收集完后清空,以便于收集下一个函数
msg='hello world'
//Observer
function observer(data){
for(let key in data){
let temp=data[key]
let funcs=[] //这里定义一个数组来存要依赖到的函数们
Object.defineProperty(data,key,{
get:function(){
funcs.push(window.func) //每次调用这个数据,就会执行get函数,然后在这里把依赖存起来,当改变这个数据时,再去set函数里去执行所有的依赖
return temp
},
set:function(val){
temp=val
for(var i=0 ; i<funcs.length ; i++){
funcs[i]() //调用所以的依赖,页面去重新渲染
}
},
})
}
}
还应该在收集依赖时,判断是否为空,更加严谨,这里就不再写了。