zoukankan      html  css  js  c++  java
  • 手写Vue (1) 依赖收集

    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

     
  • 相关阅读:
    Centos6.5环境中安装vsftp服务
    MySQL数据库的数据备份和恢复(导入和导出)命令操作语法【转】
    linux系统被入侵后处理经历【转】
    Linux lsof命令详解和使用示例【转】
    Oracle 表空间和用户权限管理【转】
    如何在 Linux 中找出最近或今天被修改的文件
    Linux 服务器系统监控脚本 Shell【转】
    1张图看懂RAID功能,6张图教会配置服务器【转】
    简析TCP的三次握手与四次分手【转】
    TCP协议中的三次握手和四次挥手(图解)【转】
  • 原文地址:https://www.cnblogs.com/guangzhou11/p/12682262.html
Copyright © 2011-2022 走看看