實現一個簡易的vue

1./compiler ⽬目錄是編譯模版;

2./core ⽬目錄是 Vue.js 的核⼼心(也是後⾯面的重點);

3./platforms ⽬目錄是針對核⼼心模塊的 ‘平臺’ 模塊;

4./server ⽬目錄是處理理服務端渲染;

5./sfc ⽬目錄處理理單⽂文件 .vue;

6./shared ⽬目錄提供全局⽤用到的⼯工具函數。

Vue.js 的組成是由 core + 對應的 ‘平臺’ 補充代碼構成(獨立構建和運行時構建 只是 platforms 下 web 平臺的兩種選擇)。

vue的雙向數據綁定

雙向綁定(響應式原理)所涉及到的技術

1. Object.defineProperty
2. Observer
3. Watcher
4. Dep
5. Directive

1. Object.defineProperty

var obj = {};
var a;
Object.defineProperty(obj,'a',{
  get: function(){
    console.log('get val');
    return a;
  },
  set: function(newVal){
    console.log('set val:' + newVal);
    a = newVal;
  }
});
obj.a // get val;   相當於<span>{{a}}</span>
obj.a = '111'; // set val:111  相當於<input v-model="a">


setter 觸發消息到 Watcher watcher幫忙告訴 Directive 更新DOM,DOM中修改了數據 也會通知給 Watcher,watcher 幫忙修改數據。

2. Observer

觀察者模式是軟件設計模式的一種。
在此種模式中,一個目標對象管理所有相依於它的觀 察者對象,並且在它本身的狀態改變時主動發出通知。
這通常透過呼叫各觀察者所提供的 方法來實現。此種模式通常被用來實時事件處理系統。
訂閱者模式涉及三個對象:
發佈者、主題對象、訂閱者,三個對象間的是一對多的關係,
每當主題對象狀態發生改變時,其相關依賴對象都會得到通知,並被自動更新。
看一個簡單的示例:


vue裏邊怎麼操作的呢? vue observer



  1. watcher

  1. Dep

  1. Directive


弄明白原理和架構之後,我們來實現一個簡單的vue雙向數據綁定

1.這個Vue是從哪裏來的呢?


是通過上述方法實例化的一個對象;但是裏邊有兩個未知生物 observe ? Compile?

observe中寫的是雙向綁定的核心原理就是Object.defineProperty

通過set,get來設置值與獲取值

把text屬性綁定到vue實例上面去使用

那其中的Dep又是什麼呢?


添加訂閱者跟通知訂閱更新

再來看一下Compile中寫的什麼吧

function Compile(node, vm) {
  if (node) {
    this.$frag = this.nodeToFragment(node, vm);
    return this.$frag;
  }
}
Compile.prototype = {
  nodeToFragment: function (node, vm) {
    var self = this;
    var frag = document.createDocumentFragment(); // 創建一段html文檔片段
    var child;

    while (child = node.firstChild) {
      self.compileElement(child, vm);
      frag.append(child); // 將所有子節點添加到fragment中
    }
    return frag;
  },
  compileElement: function (node, vm) {
    var reg = /\{\{(.*)\}\}/;

    //節點類型爲元素
    if (node.nodeType === 1) {
      var attr = node.attributes;
      // 解析屬性
      for (var i = 0; i < attr.length; i++) {
        if (attr[i].nodeName == 'v-model') {
          var name = attr[i].nodeValue; // 獲取v-model綁定的屬性名
          node.addEventListener('input', function (e) {
            // 給相應的data屬性賦值,進而觸發該屬性的set方法
            // 觸發set vm[name]
            vm[name] = e.target.value;
          });
          // node.value = vm[name]; // 將data的值賦給該node
          new Watcher(vm, node, name, 'value');
        }
      };
    }
    //節點類型爲text
    if (node.nodeType === 3) {
      if (reg.test(node.nodeValue)) {
        var name = RegExp.$1; // 獲取匹配到的字符串
        name = name.trim();
        // node.nodeValue = vm[name]; // 將data的值賦給該node
        new Watcher(vm, node, name, 'nodeValue');
      }
    }
  },
}

哦,原來Compile中是渲染html的啊。其中的Watcher是不是監控節點變化,然後給Dep通知的呢?

function Watcher(vm, node, name, type) {
    Dep.target = this;
    this.name = name; //text
    this.node = node; // 節點
    this.vm = vm; // vue實例
    this.type = type; //nodeValue 當前節點的值
    this.update();
    Dep.target = null;
}

Watcher.prototype = {
    update: function() {
        this.get();
        var batcher = new Batcher();
        batcher.push(this);
        // this.node[this.type] = this.value; // 訂閱者執行相應操作
    },
    cb:function(){
        this.node[this.type] = this.value; // 訂閱者執行相應操作
    },
    // 獲取data的屬性值
    get: function() {
        this.value = this.vm[this.name]; //觸發相應屬性的get
    }
}

哎呦,咱們猜對了呢,這樣雙向數據綁定馬上就要完成了,只剩一個Vue.nextTick()的地方了

/**
 * 批處理構造函數
 * @constructor
 */
function Batcher() {
    this.reset();
}

/**
 * 批處理重置
 */
Batcher.prototype.reset = function () {
    this.has = {};
    this.queue = [];
    this.waiting = false;
};

/**
 * 將事件添加到隊列中
 * @param job {Watcher} watcher事件
 */
Batcher.prototype.push = function (job) {
    if (!this.has[job.name]) {
        this.queue.push(job);
        this.has[job.name] = job;
        if (!this.waiting) {
            this.waiting = true;
            setTimeout(() => {
                this.flush();
            });
        }
    }
};

/**
 * 執行並清空事件隊列
 */
Batcher.prototype.flush = function () {
    this.queue.forEach((job) => {
        job.cb();
    });
    this.reset();
};

看完後是不是覺得超簡單呢?

vue3版本將做出巨大的變化,把Dep跟Watcher都幹掉了,html直接跟數據進行綁定,等vue3出來後,在寫一篇關於vue的文章吧

看完後能幫我點個贊嗎?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章