實現 VUE 中 MVVM – step13 – inject & 總結

aco發表於2018-05-14

看這篇之前,如果沒有看過之前的文章,移步檢視:

  1. 實現 VUE 中 MVVM – step1 – defineProperty
  2. 實現 VUE 中 MVVM – step2 – Dep
  3. 實現 VUE 中 MVVM – step3 – Watcher
  4. 實現 VUE 中 MVVM – step4 – 優化Watcher
  5. 實現 VUE 中 MVVM – step5 – Observe
  6. 實現 VUE 中 MVVM – step6 – Array
  7. 實現 VUE 中 MVVM – step7 – Event
  8. 實現 VUE 中 MVVM – step8 – 優化Event
  9. 實現 VUE 中 MVVM – step9 – Vue
  10. 實現 VUE 中 MVVM – step10 – Computed
  11. 實現 VUE 中 MVVM – step11 – Extend
  12. 實現 VUE 中 MVVM – step12 – props

provide / inject

在上一步我們實現了,父子元件,和 props 一樣 provide / inject 也是基於父子元件實現的,相比於 props 它的實現還要更簡單一點。我們先來看看官網上對 provide / inject 的描述。

這對選項需要一起使用,以允許一個祖先元件向其所有子孫後代注入一個依賴,不論元件層次有多深,並在起上下游關係成立的時間裡始終生效。

首先,由官網的例子可知,provide 的值是靜態的,並不會去繫結到 data 中的內容。

so 靜態的,簡單~,那實現一下。

export class Vue extends Event {
    ···
    _init(options) {
        ···
        // 用例項下的 _provide 屬性,儲存傳入的 provide
        vm._provide = vm.$options.provide

        // 從父元件的 _provide 取對應屬性,若沒有繼續往上找,直到找到根節點
        // 若找到根節點還沒有,就使用預設值
        let inject = vm._inject = {}
        for (let key in  vm.$options.inject) {
            inject[key] = getProvideForInject(vm, key, vm.$options.inject[key].default)
        }
        // 代理到 this 下
        for (let key in inject) {
            proxy(vm, `_inject`, key)
        }
    }
}

測試程式碼:

import {Vue} from `./Vue.mjs`

let test = new Vue({
    provide: {
        foo: `bar`
    },
    components: {
        sub: {
            inject: {
                foo: {default: `foo`},
                bar: {default: `subBar`}
            },
            components: {
                subSub: {
                    inject: {
                        foo: {default: `foo`},
                        bar: {default: `subSubBar`}
                    }
                }
            }
        }
    }
})

let testSubClass = Vue.extend(test.$options.components.sub)
let testSub = new testSubClass({parent: test})

let testSubSubClass = Vue.extend(testSub.$options.components.subSub)
let testSubSub = new testSubSubClass({parent: testSub})

console.log(testSub.foo)
// bar
console.log(testSub.bar)
// subBar
console.log(testSubSub.foo)
// bar
console.log(testSubSub.bar)
// subSubBar

檢視完整的程式碼

ok 其實這對屬性的實現挺簡單的,就是取值而已。

到此為止,Vue 中關於資料繫結的部分基本上實現的差不多了(不包括directives/filters/slot/ref···這些與頁面渲染的東西)

但也有以下東西沒實現內容簡單就不過多的介紹了

  1. mixins: 就是 options 的合併
  2. 生命週期函式: 在特定的時間觸發特定名稱的事件即可
  3. $nextTick: 可以去看看 JS Event Loop 的相關內容,優先使用微任務來實現

接下來我們來想想,目前我們實現的東西都能幹嘛?

總結

總的來說,我們實現了一個可響應的物件,我們可以拿到這個物件下資料的變化。

通過裝作這些變化,我們實現了 ComputedWatcher 從而到達了資料變化觸發函式的過程。

於此同時,我們還實現了 Event 來擴充套件這個可響應的結構,讓這個物件擁有了觸發和響應事件的能力。

最後我們實現了例項的樹結構,在這個基礎上實現了 propsprovide/inject

那麼還是那個問題,這個東西能幹嘛用?

我想了想,前端的應用很明顯,我們只要加一個檢視層的渲染函式,就能補充成一個 MVVM 框架,Vue 也是在這個基礎上實現的。當然你也可以實現自己虛擬節點,創造一個屬於你自己的 MVVM 框架。

或者小型的專案,並不需要虛擬節點,那麼繫結一個 HTML 渲染函式即可,所以我們實現的這個可響應結構對於 MVVM 來說,僅僅少了一層 VIEW ,所以我想叫 MVM 也是沒問題的。

但是我想這個東西是純 Js 的,所以能發揮的能力也肯定不僅僅是在前端,我之所以將這個完全的脫離模板來分析,也是想把這塊單獨出來成為一個工具。

對於這個可響應結構,我想了想用處:

  1. 專案自動化配置,打包,初始化
  2. 根據配置篩選資料
  3. ···

對於第一點,假設我們有一個專案的配置(一個 js 物件),然後我們把這個物件變成響應結構,那麼當這個物件發生變化的時候,比如說版本號變動,那麼可以觸發更新程式碼,打包編譯程式碼,傳送程式碼到服務等一些列的步驟。

對於第二點,假設在後端,我們有一堆資料,我們的需求是根據需求去篩選資料,比如 pageNo/pageSize 等等,那麼我們可以根據需求定下一個 js 配置物件,然後針對每個屬性新增一系列定義好的 Watcher ,那麼我們就可以根據這個物件的變動執行特定的方法,而我們所需要做的僅僅是把配置物件的屬性改一下就好,比如說當執行 obj.pageNo = 2 ,然後程式就自動的把對應的資料給篩選出來了。

當然,這個可響應的結構的用處遠不至於此,只要以資料驅動或是配置化的地方,都有用武之地。

ok finally 這個系列的文章算是結束了,至於 VUE 中關於,模板解析和虛擬 DOM 的實現,會有單獨的系列,但模板解析大部分是在正則解析,所以可能會沒有。

最後,根據我們的實現,這是最終的產出,一個 MVM 框架,瞭解一下

readme 還在寫,測試程式碼也還在寫,怎麼用也還在寫,總之現在還是個雛形吧~~

相關文章