vue实现数据双向绑定原理



  function Dep() {
    this.subs = {}; // 仓库
  }
  
  Dep.prototype.addSub = function (sub, name) {
    // sub = 对应的span {{}}
    this.subs[name] = sub;
  };
  
  Dep.prototype.notify = function (name) {
    // sub = 对应的span {{}}
    this.subs[name].update();
  };
  
  function Watcher(vm, node, name) {
    // 把内容通过this的方式保存起来 , 添加到Dep仓库里
    // 这里相当于定义了一个对象 把对象保存到dep仓库里
    Dep.target = this;
    this.name = name;
    this.vm = vm;
    this.node = node;
    this.update();
    Dep.target = null;
  }
  
  Watcher.prototype.update = function () {
    this.node.innerHTML = this.vm[this.name]
  };
  
  /*var Dep = (function () {
      var subs = {};
      return {
        addSub: function (value) {
          subs = value
        }
      }
  }());*/
  
  function compile(node, vm) {
    var reg = /\{\{(.*)\}\}/;
    var name;
    if (node.nodeType === 1) {
      if (node.hasAttribute("v-model")) {
        name = node.getAttribute("v-model");
        node.addEventListener("input", function (e) {
          vm[name] = e.target.value;
        });
        // 文本框默认的value = 实例化对象身上对应的set get的数据
        node.value = vm[name];
        node.removeAttribute("v-model");
      } else if (reg.test(node.innerText)) {
        name = RegExp.$1;
        name = name.trim();// 清楚左右的空格
        node.innerText = vm[name]; // 把{{}}所在的元素节点内容改变成对应的数据
        new Watcher(vm, node, name);// 把元素保存起来方便以后使用
      }
    }
  }
  
  
  // 处理(整理)原始dom
  function nodeToFragment(node, vm) {
    // 创建代码片段
    var flag = document.createDocumentFragment();
    var child;
    while (child = node.firstChild) {
      // 整理dom 把v-model 之类的东西处理之后
      // ......
      compile(child, vm);
      flag.appendChild(child);
    }
    return flag;
  }


  
  function defineReactive(vm, key, value) {
    var dep = new Dep();
    Object.defineProperty(vm, key, {
      get: function () {
        Dep.target && dep.addSub(Dep.target, key);
        return value;
      },
      set: function (newVlaue) {
        value = newVlaue;
        // 让{{}}更新
        dep.notify(key);
      }
    })
  }
  
  function observe(data, vm) {
    for (var key in data) {
      defineReactive(vm, key, data[key]);
    }
  }
  
  function Wulv(options) {
    this.data = options.data;
    observe(this.data, this);
    var el = document.getElementById(options.el);
    var dom = nodeToFragment(el, this);
    el.appendChild(dom);

  }
  
  var app = new Wulv({
    el: "app",// 范围
    data: {
      name: "name",
      age: 18,
      goudan: "goudan"
    }
  });
  
  // 1.把接收到 的数据进行get set
  // 2.处理dom 把v-model  {{}}
  // 3.同时把{{}}所在的节点保存起来
  // 触发set(input事件触发的时候)
  // 让原有的值 = 新的值(刚刚在input里输入的内容)
  // 让对应的{{}}所在的节点的内容更新
  /*new Vue({
    el: "#app",
    data: {
      name: "wulv",
      age: 18
    }
  })*/
  /*var obj = {};
  function goudan() {
    this.goudan = "goudan";
    obj.target = this;
    // this 指向的实例化对象
  }
  // var a = new goudan();
  // a 实例化对象
  console.log(a === obj.target);*/

猜你喜欢

转载自blog.csdn.net/weixin_42467138/article/details/80707735