淺析vue中雙向數據綁定

 一:雙向數據綁定

簡介:  

vue是一個mvvm框架,即數據雙向綁定,即當數據發生變化的時候,視圖也就發生變化,當視圖發生變化的時候,數據也會跟        着同步變化。

原理:

var obj = {
      foo: 'foo'
    }

    Object.defineProperty(obj, 'foo', {
      get: function () {
        console.log('將要讀取obj.foo屬性');
      }, 
      set: function (newVal) {
        console.log('當前值爲', newVal);
      }
    });

    obj.foo; // 將要讀取obj.foo屬性
    obj.foo = 'name'; // 當前值爲 name


//  get爲我們訪問屬性時調用,set爲我們設置屬性值時調用。
  • vue.js 是採用數據劫持結合發佈者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變動時發佈消息給訂閱者,觸發相應的監聽回調。

  • 第一步:需要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter和getter。這樣的話,給這個對象的某個值賦值,就會觸發setter,那麼就能監聽到了數據變化;

  • 第二步:compile解析模板指令,將模板中的變量替換成數據,然後初始化渲染頁面視圖,並將每個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變動,收到通知,更新視圖;

  • 第三步:Watcher訂閱者是Observer和Compile之間通信的橋樑,主要做的事情是:

    • 1、在自身實例化時往屬性訂閱器(dep)裏面添加自己

    • 2、自身必須有一個update()方法

    • 3、待屬性變動dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調,則功成身退。

  • 第四步:MVVM作爲數據綁定的入口,整合Observer、Compile和Watcher三者,通過Observer來監聽自己的model數據變化,通過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通信橋樑,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據model變更的雙向綁定效果。

                         

二:diff流程

1:當數據發生變化時,vue是怎麼更新節點的?

   我們先根據真實DOM生成一顆virtual DOM,當virtual DOM某個節點的數據改變後會生成一個新的Vnode,然後VnodeoldVnode作對比,發現有不一樣的地方就直接修改在真實的DOM上,然後使oldVnode的值爲Vnode

diff的過程就是調用名爲patch的函數,比較新舊節點,一邊比較一邊給真實的DOM打補丁,更新相應的視圖。

                                   

2. virtual DOM和真實DOM的區別?

virtual DOM是將真實的DOM的數據抽取出來,以對象的形式模擬樹形結構。比如dom是這樣的:

<div>
    <p>123</p>
</div>

對應的virtual DOM(僞代碼):

var Vnode = {
    tag: 'div',
    children: [
        { tag: 'p', text: '123' }
    ]
};

VNodeoldVNode都是對象

3:diff流程

  • patch函數接收兩個參數oldVnode和Vnode分別代表新的節點和之前的舊節點
    • 判斷兩節點是否值得比較,值得比較則執行patchVnode;
    • 不值得比較則用Vnode替換oldVnode;
  • patchVnode:當我們確定兩個節點值得比較之後我們會對兩個節點指定patchVnode方法;
    • 找到對應的真實dom,稱爲el;
    • 判斷Vnode和oldVnode是否指向同一個對象,如果是,那麼直接return;
    • 如果他們都有文本節點並且不相等,那麼將el的文本節點設置爲Vnode的文本節點;
    • 如果oldVnode有子節點而Vnode沒有,則刪除el的子節點;
    • 如果oldVnode沒有子節點而Vnode有,則將Vnode的子節點真實化之後添加到el;
    • 如果兩者都有子節點,則執行updateChildren函數比較子節點,這一步很重要;
  • updateChildren函數圖解

現在分別對oldS、oldE、S、E兩兩做sameVnode比較,有四種比較方式,當其中兩個能匹配上那麼真實dom中的相應節點會移到Vnode相應的位置,這句話有點繞,打個比方:

  • 如果是oldS和E匹配上了,那麼真實dom中的第一個節點會移到最後;
  • 如果是oldE和S匹配上了,那麼真實dom中的最後一個節點會移到最前,匹配上的兩個指針向中間移動;
  • 如果四種匹配沒有一對是成功的,那麼遍歷oldChild,S挨個和他們匹配,匹配成功就在真實dom中將成功的節點移到最前面,如果依舊沒有成功的,那麼將S對應的節點插入到dom中對應的oldS位置,oldS和S指針向中間移動。

 

 

 

 

 

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