摘要:我們都知道分為普通和作用域,兩個(gè)內(nèi)容都很多,所以分兩部分進(jìn)行講述。今天講的是普通其實(shí)普通,表示默認(rèn)和具名,只是他們的處理方式都差不多,就只是是否有自定義名字而已,所以,表示一種類型。
寫文章不容易,點(diǎn)個(gè)贊唄兄弟
專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧
研究基于 Vue版本 【2.5.17】
如果你覺得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧
【Vue原理】Slot - 源碼版之普通插槽
今天我們來解讀Slot 的源碼啦。我們都知道 Slot 分為 普通Slot 和 作用域Slot,兩個(gè)內(nèi)容都很多,所以分兩部分進(jìn)行講述。
今天講的是普通Slot!
其實(shí)普通Slot,表示默認(rèn)Slot和 具名Slot,只是他們的處理方式都差不多,就只是是否有自定義名字而已,所以,表示一種類型。
而我們就以默認(rèn)Slot為例去探索,讓我們先設(shè)置一個(gè)模板例子
父組件模板
test 組件被定義在父組件中
new Vue({ el: document.getElementsByTagName("div")[0], components: { test: { template: `我在子組件里面 ` } }, data() { return { name: 11 } } })
分兩個(gè)問題去看
1、插槽內(nèi)容怎么解析
2、插槽如何插子頁(yè)面
插槽內(nèi)容怎么解析插槽的作用域,是父實(shí)例。就是說,普通插槽的變量,都是從父實(shí)例上獲取的,比如上面例子插槽內(nèi)的name
根據(jù)上面的例子,父組件被解析成下面的渲染函數(shù)
with(this) { return _c("div", {}, [ _c("test", [ "我是放在組件的 slot " + name ]) ], 1) }
父渲染函數(shù)執(zhí)行時(shí),會(huì)綁定父實(shí)例為執(zhí)行作用域,根據(jù) with 的作用,test 的 slot 內(nèi)的變量name,就會(huì)訪問父實(shí)例上的name。
那么,當(dāng)父渲染函數(shù)執(zhí)行時(shí),test組件的slot,所有變量訪問父實(shí)例,并開始解析,解析的流程跟普通的模板節(jié)點(diǎn)是一樣的
插槽怎么插入子組件當(dāng)父渲染函數(shù)執(zhí)行完畢,會(huì)得到一個(gè)完整的VNode,上面存儲(chǔ)著描述DOM 的所有信息,用于去創(chuàng)建需要的DOM。
上面的父組件,會(huì)得到這么一個(gè)vnode
{ tag:"div", children:[ { tag:"test", children:["我是放在組件的 slot 11"] } ] }
可以看到
1、test組件, 被當(dāng)做是 父組件的一個(gè)子元素
2、test 組件內(nèi)的slot ,被當(dāng)做是 test元素的子元素
雖然,并不會(huì)存在 test 這種標(biāo)簽的元素,但是Vue統(tǒng)一對(duì)待,后面才會(huì)特殊處理
1、test 組件內(nèi)部解析
當(dāng)父組件解析成功,得到一個(gè)vnode,那么下一步就是patch(創(chuàng)建DOM并插入頁(yè)面)
此時(shí),Vue會(huì)按照渲染好的vnode,生成對(duì)應(yīng)的DOM 樹,并插入到頁(yè)面中
當(dāng)Vue遍歷到上面的vnode的children時(shí),遇到了 test 這個(gè)節(jié)點(diǎn),發(fā)現(xiàn)沒有test這種標(biāo)簽,認(rèn)定他是一個(gè)組件之后,會(huì)當(dāng)做一個(gè)組件去解析
這個(gè)解析的流程不會(huì)戲說細(xì)說,不屬于Slot 的內(nèi)容,后面的文章會(huì)講
2、Slot 轉(zhuǎn)存
解析 test 組件時(shí),使用 _init 方法初始化 test 組件的實(shí)例
Vue.prototype._init = function(options) { var vm = this; if (如果是組件) { initInternalComponent(vm, options); } initRender(vm); }
初始化test實(shí)例時(shí),上面的兩個(gè)方法會(huì)起到轉(zhuǎn)存 Slot 的作用
1、initInternalComponent 把 test 組件插槽節(jié)點(diǎn) 【 ["我是放在組件的 slot 11"] 】 傳給組件選項(xiàng)的 【_renderChildren】 中
function initInternalComponent(vm, options) { // 這個(gè)options是全局選項(xiàng)和組件設(shè)置選項(xiàng)的合集 var opts = vm.$options = Object.create(vm.constructor.options); var componentOptions = parentVnode.componentOptions; // 傳給組件選項(xiàng)_renderChildren opts._renderChildren = componentOptions.children; }
2、initRender 把上一步保存在 組件選項(xiàng)的【_renderChildren】 放在實(shí)例的【$slot】中
function initRender(vm) { var options = vm.$options; // 保存給組件實(shí)例上 vm.$slots = resolveSlots(options._renderChildren, renderContext); } function resolveSlots(children, context) { var slots = {}; for (var i = 0,l = children.length; i < l; i++) { var child = children[i]; var data = child.data; if (如果是具名slot) {} else { (slots.default || (slots.default = [])).push(child); } } return slots }
看父組件下的 test 組件的 vnode
{ tag:"test", children:["我是放在組件的 slot 11"] }
經(jīng)過這兩步處理,插槽節(jié)點(diǎn) 轉(zhuǎn)存到了實(shí)例上(因?yàn)闆]有給名字,所以默認(rèn)是default,如果給了名字,就是你給的)
testVm.$slot={ default: ["我是放在組件的 slot 11"] }
3、slot 替換到子組件
緊接著,test 實(shí)例化初始化完畢,開始使用組件模板去構(gòu)建他的渲染函數(shù)
模板被解析成下面的渲染函數(shù)
with(this) { return _c("main", [ "我在子組件里面", _t("default") ], 2) }
你可以看到,子組件的模板中的占位符 slot,被解析成了 _t 函數(shù)
_t("default")
然后,test 渲染函數(shù)執(zhí)行,其中 _t("default") 先執(zhí)行
_t 是 renderSlot 函數(shù),Vue 會(huì)給每個(gè)實(shí)例都保存一個(gè) _t
作用是根據(jù)傳入的名字,返回實(shí)例上$slot 保存的對(duì)應(yīng)的 【插槽節(jié)點(diǎn)】
function installRenderHelpers(target) { target._t = renderSlot; } function renderSlot(name) { return this.$slots[name] }
_t("default") 執(zhí)行完畢,返回插槽節(jié)點(diǎn),于是 test 組件渲染函數(shù)就變成下面
with(this) { return _c("main", [ "我在子組件里面", ["我是放在組件的 slot 11"] ], 2) }
現(xiàn)在,Slot 就完全插入到子組件中啦,剩下的部分,就是渲染DOM 流程,已經(jīng)跟 slot 沒有關(guān)系啦
用一張圖來看下流程
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105293.html
摘要:通過函數(shù)參數(shù)傳遞的形式,讓插槽的變量,在解析時(shí),先訪問函數(shù)變量。那么這兩個(gè)有什么關(guān)系呢外殼節(jié)點(diǎn)保存著所有父組件里給這個(gè)子組件綁定的數(shù)據(jù),比如,插槽等。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面...
摘要:寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注源碼分享,文章分為白話版和源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于版本如果你覺得排版難看,請(qǐng)點(diǎn)擊下面鏈接或者拉到下面關(guān)注公眾號(hào)也可以吧原理白話版插槽作為組件一個(gè)重要的部 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于...
摘要:結(jié)合我們的例子,子組件則會(huì)生成以下代碼到目前為止,對(duì)于普通插槽和作用域插槽已經(jīng)談的差不多了。下面我們將仔細(xì)談?wù)勥@塊的內(nèi)容。在看具體實(shí)現(xiàn)邏輯前,我們先通過一個(gè)例子來先了解下其基本用法然后進(jìn)行使用頁(yè)面展示效果如下看著好。本篇文章是細(xì)談 vue 系列第二篇了,上篇我們已經(jīng)細(xì)談了 vue 的核心之一 vdom,傳送門 今天我們將分析我們經(jīng)常使用的 vue 功能 slot 是如何設(shè)計(jì)和實(shí)現(xiàn)的,本文將圍...
摘要:一旦我們檢測(cè)到這些子樹,我們可以把它們變成常數(shù),這樣我們就不需要了在每次重新渲染時(shí)為它們創(chuàng)建新的節(jié)點(diǎn)在修補(bǔ)過程中完全跳過它們。否則,吊裝費(fèi)用將會(huì)增加好處大于好處,最好總是保持新鮮。 寫文章不容易,點(diǎn)個(gè)贊唄兄弟 專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,...
摘要:因?yàn)槭ソ裹c(diǎn)之后被強(qiáng)制更新了一波嗯,這就是的作用,把頁(yè)面上的顯示值也過濾一遍 寫文章不容易,點(diǎn)個(gè)贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內(nèi)部詳情,讓我們一起學(xué)習(xí)吧研究基于 Vue版本 【2.5.17】 如果你覺得排版難看,請(qǐng)點(diǎn)擊 下面鏈接 或者 拉到 下面關(guān)注公眾號(hào)也可以吧 【Vue原理】VModel - 源碼版之input詳...
閱讀 1751·2021-09-26 09:46
閱讀 3032·2021-09-22 15:55
閱讀 2620·2019-08-30 14:17
閱讀 3037·2019-08-26 11:59
閱讀 1819·2019-08-26 11:35
閱讀 3164·2019-08-26 10:45
閱讀 3162·2019-08-23 18:28
閱讀 1147·2019-08-23 18:21