实现一个迷你版的vue

1,094 阅读1分钟
class Vue {

  constructor(options) {

    const data = options.data;

    this._data = data;

    _proxy(this'_data'data)

    observe(data)

    new Watch(this, function () {

      return data.name;

    }, function () {

      console.log(this.value)

    })

  }

}


const _proxy = function (vm, sourceKey, data) {

  const keys = Object.keys(data);

  keys.forEach(key => {

    Object.defineProperty(vm, key, {

      get() {

        return vm[sourceKey][key]

      },

      set(val) {

        vm[sourceKey][key] = val

      }

    }

    )

  })

}

const observe = function (data) {

  const ob = new Observer(data)

}

// 观察者

class Observer {

  constructor(data) {

    this.walk(data)

  }

  walk(data) {

    Object.keys(data).forEach(key => {

      defineReactive(data, key)

    })

  }

}

// 响应

const defineReactive = function (obj, key) {

  let val = obj[key];

  const dep = new Dep();


  Object.defineProperty(obj, key, {

    enumerable: true,//是否可以枚举

    configurable: true,//是否可以修改删除

    get() {

      // 收集依赖

      dep.depend();

      return val;

    },

    set(newVal) {

      val = newVal;

      // 触发更新

      dep.notify();

    }

  })

}


// 依赖收集

Dep.uid = 0;

Dep.target = null;

class Dep {

  constructor() {

    this.id = Dep.uid++;

    this.subs = [];

  }

  addSub(sub) {

    this.subs.push(sub)

  }

  depend() {

    if (Dep.target) {

      Dep.target.addDep(this)

    }

  }

  removeSub() {

    const subIndex = this.subs.indexOf(sub);

    this.subs.splice(subIndex, 1)

  }

  notify() {

    this.subs.forEach(sub => sub.update())

  }

}

// 监听

class Watch {

  constructor(vm, render, cb) {

    // 绑定参数

    this.vm = vm;

    this.render = render;

    this.cb = cb;
    

    this.deps = [];

    this.depsIds = new Set();

    this.newDeps = [];

    this.newDepsIds = new Set();
    

    this.value = this.get();

    this.cb = cb(this.value);

  }

  // 获取值

  get() {

    Dep.target = this;

    this.newDeps = [];

    this.newDepsIds = new Set();

    this.value = this.render();

    Dep.target = null;


    this.deps.forEach(oldDep => {

      const notExistInNewDeps = !this.newDepsIds.has(oldDep.id);

      if (notExistInNewDeps) {

        oldDep.removeSub(this)

      }

    })


    this.deps = this.newDeps;

    this.depsIds = this.newDepsIds;

    return this.value;

  }

  // 添加依赖

  addDep(dep) {

    const depId = dep.id;

    if (!this.newDepsIds.has(depId)) {

      this.newDeps.push(dep);

      this.newDepsIds.push(depId);

      if (!this.depsIds.has(depId)) {

        dep.addSub(this)

      }

    }

  }

  // 更新

  update() {

    this.value = this.get();

    this.cb(this.value);

  }

}

\