手写Vue (1) 依赖收集

自闭症网瘾萝莉.ら 提交于 2020-04-12 08:35:07

1.在执行get()前进行依赖收集 更新后 清除依赖

get() {
    // 渲染watch  Dep.target = watcher;
    // msg 变化了 需要重新执行watch
    pushTarget(this)
    // 让当前传入的函数执行
    this.getter();
    popTarget()
  }

2.添加dep.js 文件 

let id = 0;
class Dep {
  constructor() {
    this.id = id++;
    this.subs = []
  }
  // 订阅
  addSub(watcher) {
    this.subs.push(watcher)
  }
  // 发布
  notify() {
    this.subs.forEach(watcher => {
      watcher.update()
    })
  }
  depend() {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }
}
// 保存当前的watcher
let stack = [];
export function pushTarget(watcher) {
  Dep.target = watcher;
  stack.push(watcher)
}
// 取出
当前的watcher
export function popTarget(watcher) { stack.pop(watcher) Dep.target = stack[stack.length - 1] } // 收集依赖 export default Dep;

添加发布 订阅 

addSub(watcher) {
    this.subs.push(watcher)
  }

将 所有 的  watcher  添加到数组 中 

 notify() {
    this.subs.forEach(watcher => {
      watcher.update()
    })
  }

将数组中的所有  watcher 拿出 执行   update 方法

 

3. 在对象进行  Object.defineProperty 执行  get 方法的时候 进行判断 

if (Dep.target) {
        dep.depend();
        debugger;
        // 数组的依赖收集 对象不存在
        if (childObj) {
          console.log(11111000)
          // 数组也收集依赖
          childObj.dep.depend()
          dependArray(value);
        }
      }

 先引入 dep 

let dep = new Dep()

如果  Dep.target 有值  调用   dep.depend(); 方法 也就是

 depend() {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }

渲染watcher  记忆住 Dep 

执行  set 方法的时候  发布通知 

set(newValue) {
      if (newValue !== value) return;
      observe(newValue)
      value = newValue
      dep.notify()
    }

通知调用 dep的 notify 方法 

// 发布
  notify() {
    this.subs.forEach(watcher => {
      watcher.update()
    })
  }

在这个方法中调用了 update 方法 update  又调用了 get  方法 

update() {
    this.get()
  }

get 方法进行以下操作 又调用了 getter 方法 

get() {
    // 渲染watch  Dep.target = watcher;
    // msg 变化了 需要重新执行watch
    pushTarget(this)
    // 让当前传入的函数执行
    this.getter();
    popTarget()
  }
getter 方法调用了 Vue.prototype.$update 方法进行  编译更新数据 



完整 的 dep.js 和watch.js文件

let id = 0;
class Dep {
  constructor() {
    this.id = id++;
    this.subs = []
  }
  // 订阅
  addSub(watcher) {
    this.subs.push(watcher)
  }
  // 发布
  notify() {
    this.subs.forEach(watcher => {
      watcher.update()
    })
  }
  depend() {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }
}
// 保存当前的watcher
let stack = [];
export function pushTarget(watcher) {
  Dep.target = watcher;
  stack.push(watcher)
}
export function popTarget(watcher) {
  stack.pop(watcher)
  Dep.target = stack[stack.length - 1]
}
// 收集依赖
export default Dep;
let id = 0;
import { pushTarget, popTarget } from './dep'
class Watcher {
  // watch 有唯一标识
  constructor(vm, exprOrfn, cb = () => { }, opts = {}) {
    // exprOrfn 表达式  cb 回调
    this.vm = vm;
    this.exprOrfn = exprOrfn;
    if (typeof exprOrfn == 'function') {
      // getter 就是  Watcher 传入的第2个函数
      this.getter = exprOrfn;
    }
    this.cb = cb;
    this.opts = opts;
    this.id = id++;
    this.deps = [];
    this.depsId = new Set();
    this.get()
  }
  get() {
    // 渲染watch  Dep.target = watcher;
    // msg 变化了 需要重新执行watch
    pushTarget(this)
    // 让当前传入的函数执行
    this.getter();
    popTarget()
  }
  update() {
    this.get()
  }
  addDep(dep) {
    let id = dep.id;
    if (!this.depsId.has(id)) {
      this.depsId.add(id)
      this.deps.push(dep)
      dep.addSub(this)
    }
  }
}
export default Watcher;

observe.js 文件

// 定义响应式的数据变化
import { observe } from './index'
import { observerArray } from './array'
import { arrayMethod } from './array'
import Dep from './dep';
export function dependArray(value) {
  console.log(2222)
  for (let i = 0; i < value.length; i++) {
    let current = value[i];
    current.__ob__ && current.__ob__.dep.depend()
    if (Array.isArray(current)) {
      dependArray(current)
    }

  }
}
export function defineReactive(data, key, value) {
  let childObj = observe(value);
  let dep = new Dep()
  Object.defineProperty(data, key, {
    get() {
      // 有值
      if (Dep.target) {
        dep.depend();
        debugger;
        // 数组的依赖收集 对象不存在
        if (childObj) {
          console.log(11111000)
          // 数组也收集依赖
          childObj.dep.depend()
          dependArray(value);
        }
      }
      return value;
    },
    set(newValue) {
      if (newValue !== value) return;
      observe(newValue)
      value = newValue
      dep.notify()
    }
  })
}
class Observe {
  constructor(data) {
    // 专门为数组
    this.dep = new Dep()
    // 每个对象都有__obj 属性,返回当前的observe实例
    Object.defineProperty(data, '__ob__', {
      get: () => this
    })
    // 数组 重写push 方法
    if (Array.isArray()) {
      // 只能拦截数组方法 数组的每一个项还需要观测
      data._proto = arrayMethod
      // 观测数组的每一个项
      observerArray(data)
    } else {
      // 对象
      // data 就是我们 定义的 vm._data 的数据
      this.walk(data)
    }
  }
  walk(data) {
    let keys = Object.keys(data);
    for (let i = 0; i < keys.length; i++) {
      let key = keys[i];  // key
      let value = data[keys[i]];  // value
      defineReactive(data, key, value)
    }
  }
}

export default Observe;

https://gitee.com/guangzhou110/handwritten_vue

 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!