成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

VUE - MVVM - part9 - Vue

yzd / 2728人閱讀

摘要:調(diào)用父類的方法類在我們上一步已經(jīng)實現(xiàn)。我們先實現(xiàn)的綁定,因為是要被監(jiān)聽,所以要進行進一步的處理。調(diào)用父類的方法方法綁定完事,其實就這么簡單。

看這篇之前,如果沒有看過之前的文章,可拉到文章末尾查看之前的文章。

前言

激動人心的時候即將來臨,之前我們做的 8 步,其實都在為這一步打基礎(chǔ),這一步,我們來簡單實現(xiàn)一個 Vue 對象,還沒有看過之前代碼的同學,請確認看過之前的文章。

主要實現(xiàn)內(nèi)容

我們從測試代碼入手,來看我們這個 Vue 實現(xiàn)了什么,然后在根據(jù)要實現(xiàn)的內(nèi)容來編寫這個 Vue 對象:

let test = new Vue({
    data() {
        return {
            baseTest: "baseTest",
            objTest: {
                stringA: "stringA",
                stringB: "stringB"
            }
        }
    },
    methods: {
        methodTest() {
            console.log("methodTest")
            this.$emit("eventTest", "事件測試")
        }
    },
    watch: {
        "baseTest"(newValue, oldValue) {
            console.log(`baseTest change ${oldValue} => ${newValue}`)
        },
        "objTest.stringA"(newValue, oldValue) {
            console.log(`objTest.stringA change ${oldValue} => ${newValue}`)
        }
    }
})

test.$on("eventTest", function (event) {
    console.log(event)
})

test.methodTest()

test.baseTest

主要實現(xiàn)的內(nèi)容有:

有屬性的監(jiān)聽 Watcher

實例下 data/methods 數(shù)據(jù)的代理(直接使用 this.xxx 就能訪問到具體的屬性/方法)

有事件 $on/$emit

實現(xiàn)

我們根據(jù)實現(xiàn)的難易程度來實現(xiàn)上面 3 點。

實現(xiàn)第 3 點,只要繼承 Event 這個類即可:

注:Vue 源碼中并不是通過這個方式實現(xiàn)的事件,有興趣的可以自己去了解下,但是在我看來這樣是最容易理解的方式。

class Vue extends Event {
    constructor() {
        // 調(diào)用父類的 constructor 方法
        super()
        ...
    }
    ...
}

Event 類在我們上一步已經(jīng)實現(xiàn)。

接著我們來處理第二點。為了方便代碼的管理,我們在類下定義一個 _init 方法,來實現(xiàn) Vue 的初始化。

我們先實現(xiàn) methods 的綁定,因為 data 是要被監(jiān)聽,所以要進行進一步的處理。

class Vue extends Event {
    constructor(options) {
        // 調(diào)用父類的 constructor 方法
        super()
        this._init(options)
    }
    
    _init(options) {
        let vm = this
        if (options.methods) {
            for (let key in options.methods) {
                vm[key] = options.methods[key].bind(vm)
            }
        }
    }
}

ok methods 方法綁定完事,其實就這么簡單。

接下來我們來處理 data ,由于 data 是需要被變換成可監(jiān)聽結(jié)構(gòu),所以我們先處理一下,然后代理到 this 對象下,如果直接賦值而不代理的話 data 的可監(jiān)聽結(jié)構(gòu)就會被破壞,我們需要一個完整的對象,這個可監(jiān)聽結(jié)構(gòu)才能完整。

這里先實現(xiàn)一下代理的方法:

export function proxy(target, sourceKey, key) {
    const sharedPropertyDefinition = {
        enumerable: true,
        configurable: true,
        get() {
        },
        set() {
        }
    }
    sharedPropertyDefinition.get = function proxyGetter() {
        return this[sourceKey][key]
    }
    sharedPropertyDefinition.set = function proxySetter(val) {
        this[sourceKey][key] = val
    }
    Object.defineProperty(target, key, sharedPropertyDefinition)
}

原理還是通過 Object.defineProperty 方法來實現(xiàn),當訪問(gettarget 下的某個屬性的時候,就會去找 target[sourceKey] 下的同名屬性,設(shè)置(settarget 下的某個屬性,就會讓設(shè)置 target[sourceKey] 下的同名屬性。這就實現(xiàn)了代理。

ok 代理實現(xiàn),我們繼續(xù)為 _init 添加方法,具體的步驟看代碼中的注釋

class Vue extends Event {
    constructor(options) {
        // 調(diào)用父類的 constructor 方法
        super()
        this._init(options)
    }
    
    _init(options) {
        let vm = this
        if (options.methods) {
            for (let key in options.methods) {
                // 綁定 this 指向
                vm[key] = options.methods[key].bind(vm)
            }
        }
        // 由于 data 是個函數(shù),所以需要調(diào)用,并綁定上下文環(huán)境
        vm._data = options.data.call(vm)
        // 將 vm._data 變成可監(jiān)聽結(jié)構(gòu),實現(xiàn) watcher 的添加
        observe(vm._data)
        // 代理屬性,這保證了監(jiān)聽結(jié)構(gòu)是一個完成的對象
        for (let key in vm._data) {
            proxy(vm, "_data", key)
        }
    }
}

最后一步,添加 watcher ,仔細分析我們在實例化時寫的 watcher

watch: {
    "baseTest"(newValue, oldValue) {
        console.log(`baseTest change ${oldValue} => ${newValue}`)
    },
    "objTest.stringA"(newValue, oldValue) {
        console.log(`objTest.stringA change ${oldValue} => ${newValue}`)
    }
}

key 為需要監(jiān)聽的屬性的路徑,value 為觸發(fā)監(jiān)聽時的回調(diào)。

ok 我們來實現(xiàn)它

class Vue extends Event {
    constructor(options) {
        super()
        this._init(options)
    }

    _init(options) {
        ...

        // 循環(huán)取出 key/value
        for (let key in options.watch) {
            // 用我們之前實現(xiàn)的 Watcher 來注冊監(jiān)聽
            // 參一:watcher 的運行環(huán)境
            // 參二:獲取注冊該 watcher 屬性
            // 參三:觸發(fā)監(jiān)聽時的回調(diào) 
            new Watcher(vm, () => {
                // 需要監(jiān)聽的值,eg: "objTest.stringA" ==> vm.objTest.stringA
                return key.split(".").reduce((obj, name) => obj[name], vm)
            }, options.watch[key])
        }

    }
}

ok watcher 也已經(jīng)實現(xiàn),以下就是完整的代碼:

export function proxy(target, sourceKey, key) {
    const sharedPropertyDefinition = {
        enumerable: true,
        configurable: true,
        get() {
        },
        set() {
        }
    }
    sharedPropertyDefinition.get = function proxyGetter() {
        return this[sourceKey][key]
    }
    sharedPropertyDefinition.set = function proxySetter(val) {
        this[sourceKey][key] = val
    }
    Object.defineProperty(target, key, sharedPropertyDefinition)
}

let uid = 0

export class Vue extends Event {
    constructor(options) {
        super()
        this._init(options)
    }

    _init(options) {
        let vm = this
        vm.uid = uid++

        if (options.methods) {
            for (let key in options.methods) {
                vm[key] = options.methods[key].bind(vm)
            }
        }

        vm._data = options.data.call(vm)
        observe(vm._data)
        for (let key in vm._data) {
            proxy(vm, "_data", key)
        }

        for (let key in options.watch) {
            new Watcher(vm, () => {
                return key.split(".").reduce((obj, name) => obj[name], vm)
            }, options.watch[key])
        }

    }
}

接下來,我們來測試一下

let test = new Vue({
    data() {
        return {
            baseTest: "baseTest",
            objTest: {
                stringA: "stringA",
                stringB: "stringB"
            }
        }
    },
    methods: {
        methodTest() {
            console.log("methodTest")
            this.$emit("eventTest", "事件測試")
        }
    },
    watch: {
        "baseTest"(newValue, oldValue) {
            console.log(`baseTest change ${oldValue} => ${newValue}`)
        },
        "objTest.stringA"(newValue, oldValue) {
            console.log(`objTest.stringA change ${oldValue} => ${newValue}`)
        }
    }
})

test.$on("eventTest", function (event) {
    console.log(event)
})

test.methodTest()
// methodTest
// 事件測試

test.baseTest = "baseTestChange"
// baseTest change baseTest => baseTestChange

test.objTest.stringA = "stringAChange"
// objTest.stringA change stringA => stringAChange

剛開始使用 Vue 的時候,感覺代碼里面都是些黑魔法,在看了源碼之后驚覺:其實 Vue 的整個實現(xiàn)并沒有什么黑魔法,有的是精心的結(jié)構(gòu)和處理,耐心點看下去,我相信我的收獲會很大。

點擊查看相關(guān)代碼

系列文章地址

VUE - MVVM - part1 - defineProperty

VUE - MVVM - part2 - Dep

VUE - MVVM - part3 - Watcher

VUE - MVVM - part4 - 優(yōu)化Watcher

VUE - MVVM - part5 - Observe

VUE - MVVM - part6 - Array

VUE - MVVM - part7 - Event

VUE - MVVM - part8 - 優(yōu)化Event

VUE - MVVM - part9 - Vue

VUE - MVVM - part10 - Computed

VUE - MVVM - part11 - Extend

VUE - MVVM - part12 - props

VUE - MVVM - part13 - inject & 總結(jié)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/94631.html

相關(guān)文章

  • VUE - MVVM - part1 - defineProperty

    摘要:在中關(guān)于如何實現(xiàn)在網(wǎng)上可以搜出不少,在看了部分源碼后,梳理一下內(nèi)容。換個說法,當我們?nèi)≈档臅r候,函數(shù)自動幫我們添加了針對當前值的依賴,當這個值發(fā)生變化的時候,處理了這些依賴,比如說節(jié)點的變化。 在 VUE 中關(guān)于如何實現(xiàn)在網(wǎng)上可以搜出不少,在看了部分源碼后,梳理一下內(nèi)容。 首先,我們需要了解一下 js 中的一個 API :Object.defineProperty(obj, prop,...

    liukai90 評論0 收藏0
  • VUE - MVVM - part7 - Event

    摘要:事件是什么在標準瀏覽器中,我們經(jīng)常使用來為一個添加一個事件等。仔細看這些情況,歸結(jié)到代碼中,無非就是一個行為或情況的名稱,和一些列的動作,而在中動作就是,一系列的動作就是一個函數(shù)的集合。 看這篇之前,如果沒有看過之前的文章,可拉到文章末尾查看之前的文章。 事件是什么? 在標準瀏覽器中,我們經(jīng)常使用:addEventListener 來為一個 DOM 添加一個事件(click、mouse...

    xialong 評論0 收藏0
  • VUE - MVVM - part2 - Dep

    摘要:看這篇之前,如果沒看過先移步看實現(xiàn)中。同樣的,在取值時收集依賴,在設(shè)置值當值發(fā)生變化時觸發(fā)依賴。中實現(xiàn)了一個的類來處理以上兩個問題,之后再說。以下語法下的,源碼中差不多就這樣點擊查看相關(guān)代碼系列文章地址優(yōu)化優(yōu)化總結(jié) 看這篇之前,如果沒看過 step1 先移步看 實現(xiàn) VUE 中 MVVM - step1 - defineProperty。 在上一篇我們大概實現(xiàn)了,Vue 中的依賴收集和...

    hover_lew 評論0 收藏0
  • VUE - MVVM - part11 - Extend

    摘要:所以方法,是對默認進行擴展,從而實現(xiàn)擴展。這里我用了這個庫提供的合并方法,用來合并兩個對象,并不會修改原對象的內(nèi)容。測試符合我們的預期,方法也就實現(xiàn)了,下一步,實現(xiàn)父子組件。系列文章地址優(yōu)化優(yōu)化總結(jié) 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 組件的擴展 在 Vue 中有 extend 方法可以擴展 Vue 的實例,在上一步中,有一些實現(xiàn)是必須要通過子父組件才...

    cartoon 評論0 收藏0
  • VUE - MVVM - part13 - inject & 總結(jié)

    摘要:通過裝作這些變化,我們實現(xiàn)了從而到達了數(shù)據(jù)變化觸發(fā)函數(shù)的過程。于此同時,我們還實現(xiàn)了來擴展這個可響應的結(jié)構(gòu),讓這個對象擁有了觸發(fā)和響應事件的能力。最后,根據(jù)我們的實現(xiàn),這是最終的產(chǎn)出,一個框架,了解一下系列文章地址優(yōu)化優(yōu)化總結(jié) 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 provide / inject 在上一步我們實現(xiàn)了,父子組件,和 props 一樣 pr...

    niuxiaowei111 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<