1.收集依赖
收集依赖就是把需要把用到响应式的对象属性的函数存起来,只要你用到了我的属性,我就把你存起来.所以,需要创建一个类,管理依赖
class Depend {
constructor(){
this.reactiveFn = new Set() //用set可以保证不会重复加入函数
}
addDepend(fn){
this.reactiveFn.add(fn) //加入到对应属性依赖
}
notify(){
this.reactiveFn.forEach(fn => {//属性改变时调用这些函数
fn()
})
}
}
2.合理储存依赖
调用上面类方法可以创建一个属性依赖,但我们需要方便管理储存多个依赖,封装一个获取依赖的函数
let weakMap = new WeakMap() //弱应用map
function getDepend(obj,key){ //把对象和属性传进来
let map = weakMap.get(obj)
if(!map){
map = new Map()
weakMap.set(obj,map)
}
let dePend = map.get(key)
if(!dePend){
map.set(key,new Depend())
dePend = map.get(key)
}
return dePend
}
3.创建依赖添加函数,响应式代理对象
依赖管理好后,创建响应式对象,添加依赖
let activeFn = null
function watchFn(fn){ //目前需手动把用到的函数添加进去
activeFn = fn
fn()
activeFn = null
}
function reactive(obj){
return new Proxy(obj,{
get:function(target,key,receiver){
// console.log( getDepend(target,key),'sm')
if(activeFn){
getDepend(target,key).addDepend(activeFn)
}
return Reflect.get(target,key,receiver) //Reflect对象方法避免直接调用原始对象
},
set:function(target,key,newVal,receiver){
Reflect.set(target,key,newVal,receiver)
// dePend.notify()
getDepend(target,key).notify()
}
})
}
4.使用
class Depend {
constructor(){
this.reactiveFn = new Set()
}
addDepend(fn){
this.reactiveFn.add(fn)
}
notify(){
this.reactiveFn.forEach(fn => {
fn()
})
}
}
let weakMap = new WeakMap()
function getDepend(obj,key){
let map = weakMap.get(obj)
if(!map){
map = new Map()
weakMap.set(obj,map)
}
let dePend = map.get(key)
if(!dePend){
map.set(key,new Depend())
dePend = map.get(key)
}
return dePend
}
let activeFn = null
function watchFn(fn){
activeFn = fn
fn()
activeFn = null
}
function reactive(obj){
return new Proxy(obj,{
get:function(target,key,receiver){
// console.log( getDepend(target,key),'sm')
if(activeFn){
getDepend(target,key).addDepend(activeFn)
}
return Reflect.get(target,key,receiver)
},
set:function(target,key,newVal,receiver){
Reflect.set(target,key,newVal,receiver)
// dePend.notify()
getDepend(target,key).notify()
}
})
}
let obj = {
name:'gw',
age:18
}
let info = {
address:'北京'
}
const objProxy = reactive(obj)
setTimeout(() => {
objProxy.name = '李白'
}, 2000);
watchFn(function(){
console.log('name用', objProxy.name)
})
watchFn(function(){
console.log('name用2',objProxy.name)
})
watchFn(function(){
console.log('age用',objProxy.age)
})