1. 程式人生 > >vue 原理簡單實現

vue 原理簡單實現

實現資料繫結的做法有大致如下幾種:

  • 釋出者-訂閱者模式(backbone.js)

  • 髒值檢查(angular.js)

  • 資料劫持(vue.js)

釋出者-訂閱者模式: 一般通過sub, pub的方式實現資料和檢視的繫結監聽,更新資料方式通常做法是 vm.set('property', value),這裡有篇文章講的比較詳細,有興趣可點這裡

這種方式現在畢竟太low了,我們更希望通過 vm.property = value這種方式更新資料,同時自動更新檢視,於是有了下面兩種方式

髒值檢查: angular.js 是通過髒值檢測的方式比對資料是否有變更,來決定是否更新檢視,最簡單的方式就是通過 setInterval() 定時輪詢檢測資料變動,當然Google不會這麼low,angular只有在指定的事件觸發時進入髒值檢測,大致如下:

  • DOM事件,譬如使用者輸入文字,點選按鈕等。( ng-click )
  • XHR響應事件 ( $http )
  • 瀏覽器Location變更事件 ( $location )
  • Timer事件( timeout ,interval )
  • 執行 digest() 或apply()

響應式

在 init 的時候 通過 Object.defineProperty 對資料屬性進行了繫結,它使得當被設定的物件被讀取的時候會執行 getter 函式,而在當被賦值的時候會執行 setter 函式。

資料劫持

vue.js 則是採用資料劫持結合釋出者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在資料變動時釋出訊息給訂閱者,觸發相應的監聽回撥。

Object.defineProperty

/*
    obj: 目標物件
    prop: 需要操作的目標物件的屬性名
    descriptor: 描述符
    return value 傳入物件
*/
Object.defineProperty(obj, prop, descriptor)
複製程式碼

descriptor的一些屬性,簡單介紹幾個屬性,具體可以參考 MDN 文件。

  • enumerable,屬性是否可列舉,預設 false。
  • configurable,屬性是否可以被修改或者刪除,預設 false。
  • get,獲取屬性的方法。
  • set,設定屬性的方法。

observer(可觀察的)


function cb (val) {
    /* 渲染檢視 */
    console.log("檢視更新啦~");
}

function defineReactive (obj, key, val) {
    Object.defineProperty(obj, key, {
        enumerable: true,       /* 屬性可列舉 */
        configurable: true,     /* 屬性可被修改或刪除 */
        get: function reactiveGetter () {
            return val;         /* 實際上會依賴收集,下一小節會講 */
        },
        set: function reactiveSetter (newVal) {
            if (newVal === val) return;
            cb(newVal);
        }
    });
}
複製程式碼

訂閱者 Dep

訂閱者 Dep ,它的主要作用是用來存放 Watcher 觀察者物件。

觀察者 Watcher

class Watcher {
    constructor () {
        /* 在new一個Watcher物件時將該物件賦值給Dep.target,在get中會用到 */
        Dep.target = this;
    }

    /* 更新檢視的方法 */
    update () {
        console.log("檢視更新啦~");
    }
}

Dep.target = null;
複製程式碼

依賴收集

當被渲染的時候,因為會讀取所需物件的值,所以會觸發 getter 函式進行「依賴收集」,「依賴收集」的目的是將觀察者 Watcher 物件存放到當前閉包中的訂閱者 Dep 的 subs 中。

在修改物件的值的時候,會觸發對應的 setter, setter 通知之前「依賴收集」得到的 Dep 中的每一個 Watcher,告訴它們自己的值改變了,需要重新渲染檢視。這時候這些 Watcher 就會開始呼叫 update 來更新檢視,當然這中間還有一個 patch 的過程以及使用佇列來非同步更新的策略。

  • 用 addSub 方法可以在目前的 Dep 物件中增加一個 Watcher 的訂閱操作;
  • 用 notify 方法通知目前 Dep 物件的 subs 中的所有 Watcher 物件觸發更新操作。

更新檢視

在修改一個物件值的時候,會通過 setter -> Watcher -> update 的流程來修改對應的檢視。

MVVM

MVVM作為資料繫結的入口,整合Observer、Compile和Watcher三者,通過Observer來監聽自己的model資料變化,通過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通訊橋樑,達到資料變化 -> 檢視更新;檢視互動變化(input) -> 資料model變更的雙向繫結效果。

原始碼實現詳解地址

vue mvvm


作者:wenli
連結:https://juejin.im/post/5ac874c06fb9a028c675f494
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。