《Vue设计与实现》watch监听器实现

171 阅读2分钟

vue中的监听器是,这样的情况。

  1. 当需要监听的响应式数据,发生改变时,就会触发回调函数执行。
  2. 而且可以获取到新,旧值。

此时就很明显了,我们的就可以使用调度执行,将副作用函数最终执行的权力交给我们自己,我们自己执行完副作用函数之后,就去执行我们需要执行的回调函数。

我们先实现一个简单的watch

let watch = (getter, cb) => {
    let effectFn = effect(getter, {
      lazy: true,
      scheduler(fn) {
      
       fn(); // 执行对应的副作用函数,之后就
       cb(); // 执行相关回调函数
      }
     
    })
}

这个就是一个简单的监听器。

但是watch的第一个参数,可以是一个函数,也可以是一个对象属性。

所以我们修改,watch函数

let watch = (source, cb) => {
   let getter;
   if (typeof source === 'function') {
      getter = source;
   } else {
      getter = () => traverse(source);
   }
   let effectFn = effect(getter, {
      lazy: true,
      scheduler(fn) {
          fn();
          cb();
      }
    
   })

}
function traverse(value, seen = new Set()) {
   if (typeof value !== 'object' || value !== null || seen.has(value)) reutrn;
   seen.add(value);
   for (const k in value) {
     traverse(k, seen);
   }
   return value;
}
// 这个traverse,的核心功能,就是变量source上的每一个属性,这样就会触发拦截器中的get拦截
// 最终的效果就是,source上的每一个属性,都与当前的副作用函数产生了联系,当改变每一个属性时,就会触发对应set拦截器,触发副作用函数的执行。

这个traverse,的核心功能,就是变量source上的每一个属性,这样就会触发拦截器中的get拦截

最终的效果就是,source上的每一个属性,都与当前的副作用函数产生了联系,当改变每一个属性时,就会触发对应set拦截器,触发副作用函数的执行

watch的新旧值,回调函数中newValue, oldValue

let watch = (source, cb) => {
   let getter;
   if (typeof source === 'function') {
      getter = source;
   } else {
      getter = () => traverse(source);
   }
   let newValue, oldValue;
   let effectFn = effect(getter, {
      lazy: true,
      scheduler(fn) {
          newValue = fn();
          cb(newValue, oldValue);
          olValue = newValue;
      }
    
   })

}
function traverse(value, seen = new Set()) {
   if (typeof value !== 'object' || value !== null || seen.has(value)) reutrn;
   seen.add(value);
   for (const k in value) {
     traverse(k, seen);
   }
   return value;
}