摘要:看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。而該組件實例的父實例卻并不固定,所以我們將這些在使用時才能確定的參數(shù)在組件實例化的時候傳入。系列文章地址優(yōu)化優(yōu)化總結(jié)
看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。
前言在上一步,我們實現(xiàn) extend 方法,用于擴展 Vue 類,而我們知道子組件需要通過 extend 方法來實現(xiàn),我們從測試?yán)觼砣胧?,看看這一步我們需要實現(xiàn)什么:
let test = new Vue({ data() { return { dataTest: { subTest: 1 } } }, components: { sub: { props: { propsStaticTest: { default: "propsStaticTestDefault" }, propsDynamicTest: { default: "propsDynamicTestDefault" } }, watch: { "propsDynamicTest"(newValue, oldValue) { console.log("propsDynamicTest newValue = " + newValue) } } } } })
從例子可知: sub 是 test 的子組件,同時 test 組件向 sub 組件傳遞了 propsStaticTest/propsDynamicTest 兩個 props 。
所以我們這一步要做兩件事
實現(xiàn)子組件生成樹結(jié)構(gòu)
實現(xiàn) props ,從例子上可以看出需要實現(xiàn)靜態(tài)和動態(tài)兩種 prop
VUE 中組件的生成雖然在之前的步驟中,我們一直沒有涉及到模板,僅僅是把頁面的渲染抽象成一個函數(shù),主要是為了把 MVVM 中的數(shù)據(jù)綁定過程給解釋清楚,但是父子組件的實現(xiàn)卻必須要通過模板來聯(lián)系,所以我們這里簡單的介紹下 Vue 中由模板到生成頁面渲染函數(shù)的過程
得到模板(DOM 字符串)或是 render 函數(shù)
分析模板,得到 HTML 語法樹(AST),生成 render 函數(shù)。如果直接給的是 render 則沒有這個步驟
由 render 函數(shù)生成 VNode 這就是虛擬樹了
將 Vnode 作為參數(shù)傳入一個函數(shù)中,就能得到 html 渲染函數(shù)
ok 看起來和組件好像沒有什么關(guān)系,我們分析下組件寫法
由上面這個標(biāo)簽我們可以得到什么?
這是一個子組件,組件名:sub
傳遞了一個靜態(tài)的 prop :propsStaticTest
傳遞了一個動態(tài)的 prop :propsDynamicTest
靜態(tài)說明這個屬性不會發(fā)生變化,動態(tài)會,最明顯的區(qū)別就是:動態(tài)屬性有 :/v-bind 修飾
結(jié)合上面的第2個步驟,會分析出一些東西。僅僅針對 props ,假設(shè)模板解析引擎會解析出下面這樣一個結(jié)構(gòu)
let propsOption = [{ key: "propsStaticTest", value: "propsStaticValue", isDynamic: false }, { key: "propsDynamicTest", value: "dataTest.subTest", isDynamic: true }]
注: 這里僅僅是我的假設(shè),方便理解,在 Vue 中的模板解析出來的內(nèi)容要比這個復(fù)雜。
ok 有了上面的鋪墊我們來實現(xiàn)父子組件和 props
父子組件實例初始化的實例我們需要做的僅僅就是保存組件之間的關(guān)系就行,ok 我們來實現(xiàn)它
class Vue extends Event { ··· _init(options) { let vm = this ··· // 獲取父節(jié)點 let parent = vm.$options.parent // 將該節(jié)點放到父節(jié)點的 $children 列表中 if (parent) { parent.$children.push(vm) } // 設(shè)置父節(jié)點和根節(jié)點 vm.$parent = parent vm.$root = parent ? parent.$root : vm // 初始化子節(jié)點列表 vm.$children = [] } }
我們需要做的僅僅就是給傳入 options 設(shè)置 parent ,就能明確組件之間的關(guān)系。
接著我們模擬一下當(dāng)模板編譯的時候碰到 的情況,具體的來說就是會執(zhí)行以下代碼:
let testSubClass = Vue.extend(test.$options.components.sub) let testSub = new testSubClass({parent: test}) console.log(testSub.$parent === test) // true
ok 現(xiàn)在我們先不想模板編譯具體是如何進行的,從這兩行代碼中,我們可以看出我們先使用了 extend 擴展了 Vue 實例,生成一個子類(testSubClass),接著我們實例化該類,傳入?yún)?shù)確定父實例。
想象下一,我們?yōu)槭裁匆謨刹桨褏?shù)傳入。
我們知道當(dāng)我們寫好子組件的配置時,子組件的內(nèi)部狀態(tài)就已經(jīng)確定了,所以我們可以根據(jù)這些固定的配置去擴展 Vue 類方便我們調(diào)用(使用的時候 new 一下就可以)。
而該組件實例的父實例卻并不固定,所以我們將這些在使用時才能確定的參數(shù)在組件實例化的時候傳入。
接著我們來想象一下,如果子組件(sub)里面還有子組件(sub-sub)會怎么樣?
使用 extend 擴展 Vue 類
確定父實例,new 的時候傳入,而這個 parent 就是 sub
這樣調(diào)用過多次之后,一顆 Vue 的實例樹就生成了,每一個節(jié)點都保留著父實例的引用,子組件列表還有根實例。
希望你的腦子里已經(jīng)長出了這顆樹~
ok 接下來我們來實現(xiàn) props
props希望你還記得下面這幾行代碼:
let propsOption = [{ key: "propsStaticTest", value: "propsStaticValue", isDynamic: false }, { key: "propsDynamicTest", value: "dataTest.subTest", isDynamic: true }]
這個是我們模擬模板編譯時關(guān)于 props 的部分產(chǎn)出,具體的來說就是鍵值對,以及是否有 :/v-bind 修飾,而我們知道在 Vue 中這個修飾符是表示是否是動態(tài)綁定,所以我在這里使用 isDynamic 來標(biāo)志。
首先我們來獲取屬性的數(shù)據(jù),由于動態(tài)綁定的 props 是取值路徑,所以我們得去父對象下獲取值。
let propsData = {} propsOption.forEach(item => { if (item.isDynamic) { // eg: "dataTest.subTest" => test.dataTest.subTest 將字符串轉(zhuǎn)換成取值 propsData[item.key] = item.value.split(".").reduce((obj, name) => obj[name], test) } else { propsData[item.key] = item.value } }) console.log(propsData) // { propsStaticTest: "propsStaticValue", propsDynamicTest: 1 }
ok 我們拿到中屬性對應(yīng)的值,接著把 propsData 給傳進去
let testSub = new testSubClass({parent: test, propsData})
接著我們在 _init 方法中來處理 props
_init(options) { ··· let props = vm._props = {} let propsData = vm.$options.propsData for (let key in vm.$options.props) { let value = propsData[key] // 如果沒有傳值,使用默認(rèn)值 if (!value) { value = vm.$options.props[key].default } props[key] = value } observe(props) for (let key in props) { proxy(vm, "_props", key) } ··· }
porps 的處理和 data 類似,需要變成可監(jiān)聽結(jié)構(gòu),代理到 this 對象下,無非 data 是從傳入的函數(shù)取值,而 props 從傳入的 propsData 中取值。
ok 直到現(xiàn)在為止,看起來都很美好,但是部分 props 是動態(tài)的,父組件相應(yīng)值的變化是需要同步到子組件中的,但目前我們還沒有實現(xiàn)父組件和子組件的聯(lián)系,僅僅是把值給取出放在子組件內(nèi)而已。
其實一看到監(jiān)聽變化就理所當(dāng)然的想到 Watcher,ok 我們用 Watcher 來實現(xiàn)它:
propsOption.forEach(item => { if (item.isDynamic) { new Watcher({}, () => { return item.value.split(".").reduce((obj, name) => obj[name], test) }, (newValue, oldValue) => { testSub[item.key] = newValue }) } })
ok 最后一步完成,完整的測試代碼
本來還想實現(xiàn)下 provide/inject 但篇幅有點大了,下一步實現(xiàn),也做個總結(jié)。
系列文章地址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://systransis.cn/yun/94884.html
摘要:通過裝作這些變化,我們實現(xiàn)了從而到達了數(shù)據(jù)變化觸發(fā)函數(shù)的過程。于此同時,我們還實現(xiàn)了來擴展這個可響應(yīng)的結(jié)構(gòu),讓這個對象擁有了觸發(fā)和響應(yīng)事件的能力。最后,根據(jù)我們的實現(xiàn),這是最終的產(chǎn)出,一個框架,了解一下系列文章地址優(yōu)化優(yōu)化總結(jié) 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 provide / inject 在上一步我們實現(xiàn)了,父子組件,和 props 一樣 pr...
摘要:在中關(guān)于如何實現(xiàn)在網(wǎng)上可以搜出不少,在看了部分源碼后,梳理一下內(nèi)容。換個說法,當(dāng)我們?nèi)≈档臅r候,函數(shù)自動幫我們添加了針對當(dāng)前值的依賴,當(dāng)這個值發(fā)生變化的時候,處理了這些依賴,比如說節(jié)點的變化。 在 VUE 中關(guān)于如何實現(xiàn)在網(wǎng)上可以搜出不少,在看了部分源碼后,梳理一下內(nèi)容。 首先,我們需要了解一下 js 中的一個 API :Object.defineProperty(obj, prop,...
摘要:所以方法,是對默認(rèn)進行擴展,從而實現(xiàn)擴展。這里我用了這個庫提供的合并方法,用來合并兩個對象,并不會修改原對象的內(nèi)容。測試符合我們的預(yù)期,方法也就實現(xiàn)了,下一步,實現(xiàn)父子組件。系列文章地址優(yōu)化優(yōu)化總結(jié) 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 組件的擴展 在 Vue 中有 extend 方法可以擴展 Vue 的實例,在上一步中,有一些實現(xiàn)是必須要通過子父組件才...
摘要:了解之后我們來實現(xiàn)它,同樣的為了方便理解我寫成了一個類這里的一般是的實例將屬性代理到實例下的構(gòu)造函數(shù)我們實現(xiàn)了代理屬性和更新計算屬性的值,同時依賴沒變化時,也是不會觸發(fā)的更新,解決了以上的個問題。 看這篇之前,如果沒有看過之前的文章,移步拉到文章末尾查看之前的文章。 回顧 先捋一下,之前我們實現(xiàn)的 Vue 類,主要有一下的功能: 屬性和方法的代理 proxy 監(jiān)聽屬性 watche...
摘要:關(guān)于中的的實現(xiàn),差不多也就這樣了,當(dāng)然這僅僅是基礎(chǔ)的實現(xiàn),而且視圖層層渲染抽象成一個函數(shù)。不同于中的實現(xiàn),這里少了很多各種標(biāo)記和應(yīng)用標(biāo)記的過程。 看這篇之前,如果沒有看過之前的文章,可拉到文章末尾查看之前的文章。 回顧 首先我們思考一下截止當(dāng)前,我們都做了什么 通過 defineReactive 這個函數(shù),實現(xiàn)了對于數(shù)據(jù)取值和設(shè)置的監(jiān)聽 通過 Dep 類,實現(xiàn)了依賴的管理 通過 Wa...
閱讀 4188·2021-11-22 13:52
閱讀 2513·2021-11-22 13:52
閱讀 3687·2021-11-19 09:59
閱讀 1191·2021-11-17 09:33
閱讀 2449·2019-08-30 10:53
閱讀 1237·2019-08-29 17:28
閱讀 1313·2019-08-29 17:03
閱讀 3104·2019-08-26 11:31