Vue2.x學習(二)Vue的MVVM模式

學習原文地址:淺探VUE的MVVM模式實現
html

一、MVVM模式思想vue

MVVM模式的思想:關注model(數據)的變化,讓MVVM框架去自動更新DOM,實現方法主要是數據劫持結合發佈訂閱模式。node


二、核心方法Object.defineProperty設計模式

Object.defineProperty是用來數據劫持的關鍵方法,vue框架是不兼容IE6~8低版本的,主要是由於它的用到了ES5中的這個Object.defineProperty的方法,並且這個方法暫時沒有很好的降級方案。
數組


該方法接收三個參數,並且都是必填的。數據結構

第一個參數:目標對象。app

第二個參數:須要定義的屬性或方法的名字。框架

第三個參數:目標屬性所持有的特性。dom

  • value:屬性的值。
  • writable:若是爲 false ,屬性的值就不能被重寫,只能爲只讀了。
  • enumerable:是否可枚舉,默認是false不可枚舉的(一般設置爲true)
  • configurable:總開關,一旦爲false,就不能再設置其餘的(value,writable, enumerable)
  • get():函數,獲取屬性值時執行的方法(不能夠和writable、value屬性共存)
  • set():函數,設置屬性值時執行的方法(不能夠和writable、value屬性共存)

  • 經過Object.defineProperty這個方法,能夠對引用數據實現監聽,獲取和修改值時分別調用get和set方法。mvvm

    三、數據劫持


    1. 先定義初始化構造函數MyVue,經過它來獲取咱們傳進來的數據data和定義的DOM節點範圍,而後把data傳進定義好的數據劫持方法observe。
    2. Observe實現了對數據的監聽,多寫一個observe的小方法用來new Observe,而且在裏面作了引用數據類型的判斷。這樣作的目的是爲了方便遞歸來實現數據結構的深層監聽。
    3. 在設置新值時,也執行了一遍observe方法,是爲了實現深度響應,由於在賦值的時候可能會賦值一個引用數據類型的值。
    看看有沒有實現數據劫持



    能夠看到對咱們所定義的data中的數據都已經有了get和set方法了,到這裏咱們對data中數據的變化都是能夠監聽的到了。

    四、數據代理

    數據代理,咱們用過vue的都知道,在實際使用中是能直接經過實例+屬性(vm.name)直接獲取到數據的,而咱們上面的代碼要獲取到數據還須要這樣myvue._data.name這樣來獲取到數據,中間多了一個 _data 的環節,這樣使用起來不是很方便的。


    下面咱們來實現讓咱們的實例this來代理( _data)數據,從而實現 myvue.name 這樣的操做能夠直接獲取到數據。


    以上代碼實現了數據代理,思想:就是在構建實例的時候,把data中的數據遍歷一遍,依次加到this上,加的過程不要忘記添加Object.defineProperty,只要是數據咱們都須要添加監聽。

    沒有實現代理前:

    能夠經過vm._data訪問



    不能經過vm.直接訪問



    實現代理後



    五、編譯模板(Compile)

    咱們已經完成對數據的劫持,也實現了this對數據的代理,name接下來作的是怎麼把數據編譯到咱們的dom節點上,也就是在View層展現咱們的數據。


    以上代碼實現咱們對數據的編譯Compile以下圖,能夠看到咱們把獲取到el下面全部的子節點都存儲到了文檔碎片 fragment 中暫時存儲了起來(放到內存中),由於這裏要去頻繁的操做DOM和查找DOM,因此移到內存中操做。

    效果圖:


    1. 先使用while循環,先把el中的全部子節點都添加到文檔碎片中;
    2. 而後經過replace方法,遍歷文檔中的全部子節點,將他們的文本節點(node.nodeType = 3)帶有{{}} 語法中的內容都獲取到,把匹配到的值拆分紅數組,而後遍歷依次去data中查找獲取,遍歷的節點若是有子節點的話繼續使用replace方法,直到反回undefined。
    3. 獲取到數據後,用replace方法替換掉文本中{{}}的整塊內容,而後在放回el元素中vm.$el.appendChild(fragment)。
    六、關聯視圖(view)與數據(model)

    如何實現經過修改數據引起視圖的變化呢?涉及到js中的經常使用的js設計模式--發佈訂閱模式。

    發佈訂閱模式的實現


    這裏用Dep方法來實現訂閱和通知,在這個類中有addSub(添加)和notify(通知)兩個方法,咱們把將要作的事情(函數)經過addSub添加進數組裏,等時機一到就notify通知裏面全部的方法執行。

    經過watcher建立的函數都會有一個update執行的方法能夠方便咱們調用。


    把定義函數的方法watcher加到了replace方法裏面,可是這裏的watcher跟剛寫編寫的多了兩個形參vm、RegExp.$1,並且寫法也新增了一些內容,由於當new Watcher的時候會引起發生幾個操做,來看完整代碼:





    1)首先看在Watcher構造函數中新增了一些私有屬性分別表明:

    • Dep.target = this(在構造函數Dep.target臨時存儲着watcher的當前實例)
    • this.vm = vm(vm = myvue實例)
    • this.exp = exp(exp = 匹配的查找的對象'obj1.name'是字符串類型的值)
    咱們存儲這些屬性後,接下來就要去獲取用exp匹配的字符串裏面對於數據也就是 vm.a.b,可是此時的exp是個字符串,你不能直接這樣取值vm[a.b]這是錯誤的語法,因此要循環去取到對應的值。


    總而言之,就是在每一個數據操做的部分,添加數據更新的功能,來實現數據的改變,使得view跟着改變。

    效果圖:


    函數調用關係

    相關文章
    相關標籤/搜索