SOURCE

console 命令行工具 X clear

                    
>
console
function myVue(options) {
  this._init(options);
}

myVue.prototype._init = function (options) {
  //options为上面使用时传入的结构体,包括了el,data,methods
  this.$options = options;
  //el是#app,this.$el是id为app的Element元素
  this.$el = document.querySelector(options.el);
  //this.$data = { number: 0 }
  this.$data = options.data;
  //this.$methods = { increment: function() {} }
  this.$methods = options.methods;
  //_binding保存着model与biew的映射关系,也就是Watcher实例
  this._binding = {};
  
  this._observe(this.$data);
  this._compile(this.$el);
}

myVue.prototype._observe = function (obj) {
  var _this = this;
  for (key in obj) {
    if (obj.hasOwnProperty(key)) {
      _this._binding[key] = {
        _directives: []
      };
      var value = obj[key];
      if (typeof value === 'object') {
        _this._observe(value);
      }
      var binding = this._binding[key];
      Object.defineProperty(_this.$data, key, {
        enumerable: true,
        configurable: true,
        get: function () {
          console.log(`获取${value}`);
          return value;
        },
        set: function (newVal) {
          console.log(`更新${newVal}`);
          if (value !== newVal) {
            value = newVal;
            binding._directives.forEach(function (item) {
              item.update();
            })
          }
        }
      })
    }
  }
}

myVue.prototype._compile = function (root) {
  var _this = this;
  var nodes = root.children;
  for (var i = 0; i < nodes.length; i++) {
    var node = nodes[i];
    if (node.children.length) {
      this._compile(node);
    }
    
    //如果有v-click属性,则监听它的onclick事件
    if (node.hasAttribute('v-click')) {
      node.onclick = (function () {
        var attrVal = nodes[i].getAttribute('v-click');
        return _this.$methods[attrVal].bind(_this.$data);
      })();
    }
    
    if (node.hasAttribute('v-model') && (node.tagName == 'INPUT' || node.tagName == 'TEXTAREA')) {
      node.addEventListener('input', (function(key) {
        var arrtVal = node.getAttribute('v-model');
        _this._binding[arrtVal]._directives.push(new Watcher(
          'input', node, _this, attrVal, 'value'
        ))
        
        return function() {
          _this.$data[attrVal] = nodes[key].value
        }
      })(i));
    }
    
    if (node.hasAttribute('v-bind')) {
      var attrVal = node.getAttribute('v-bind');
      _this._binding[attrVal]._directives.push(new Watcher(
        'text', node, _this, attrVal, 'innerHTML'
      ))
    }
  }
}

function Watcher(name, el, vm, exp, attr) {
  //指令名称
  this.name = name;
  //制定对应的DOM元素
  this.el = el;
  //指令所属myVue实例
  this.vm = vm;
  //指令对应的值,本例如“number”
  this.exp = exp;
  //绑定的属性值,本例为“innerHTML”
  this.attr = attr;
  
  this.update();
}

Watcher.prototype.update = function() {
  this.el[this.attr] = this.vm.$data[this.exp];
}

window.onload = function() {
  var app = new myVue({
    el: '#app',
    data: {
      number: 0,
      count: 0
    },
    methods: {
      increment: function() {
        this.number++;
      },
      incre: function() {
        this.count++;
      }
    }
  })
}
<div id="app">
  <form>
    <input type="text" v-model="number">
    <button type="button" v-click="increment">增加</button>
  </form>
  <h3 v-bind="number"></h3>
  
  <form>
    <input type="text" v-model="count">
    <button type="button" v-click="incre">增加</button>
  </form>
  <h3 v-bind="count"></h3>
</div>