日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > vue >内容正文

vue

slot多作用域 vue_vue 深度长文之slot 篇

發(fā)布時間:2023/12/3 vue 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 slot多作用域 vue_vue 深度长文之slot 篇 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

今天我們將分析我們經(jīng)常使用的 vue 功能 slot 是如何設(shè)計和實現(xiàn)的,本文將圍繞 普通插槽 和 作用域插槽 以及 vue 2.6.x 版本的 v-slot 展開對該話題的討論。當(dāng)然還不懂用法的同學(xué)建議官網(wǎng)先看看相關(guān) API 先。接下來,我們直接進入正文吧

普通插槽

首先我們看一個我們對于 slot 最常用的例子

然后我們直接使用,頁面則正常顯示一下內(nèi)容

然后,這個時候我們使用的時候,對 slot 內(nèi)容進行覆蓋

this is slot custom content.

內(nèi)容則變成下圖所示

對于此,大家可能都能清楚的知道會是這種情況。今天我就將帶領(lǐng)大家直接看看 vue 底層對 slot 插槽的具體實現(xiàn)。

vm.$slots

我們開始前,先看看 vue 的 Component 接口上對 $slots 屬性的定義

$slots: { [key: string]: Array };

多的咱不說,咱直接 console 一下上面例子中的 $slots

剩下的篇幅將講解 slot 內(nèi)容如何進行渲染以及如何轉(zhuǎn)換成上圖內(nèi)容

renderSlot

看完了具體實例中 slot 渲染后的 vm.$slots 對象,這一小篇我們直接看看 renderSlot 這塊的邏輯,首先我們先看看 renderSlot 函數(shù)的幾個參數(shù)都有哪些

這里我們先不看 scoped-slot 的邏輯,我們只看普通 slot 的邏輯。

const slotNodes = this.$slots[name]nodes = slotNodes || fallbackreturn nodes

這里直接先取值 this.$slots[name] ,若存在則直接返回其對其的 vnode 數(shù)組,否則返回 fallback。看到這,很多人可能不知道 this.$slots 在哪定義的。解釋這個之前我們直接往后看另外一個方法

看完 resolveSlots 的參數(shù)后我們接著往后過其中具體的邏輯。如果 children 參數(shù)不存在,直接返回一個空對象

const slots = {}if (!children) { return slots}

如果存在,則直接對 children 進行遍歷操作

slots 獲取到值后,則進行一些過濾操作,然后直接返回有用的 slots

我們從上面已經(jīng)知道了 vue 對 slots 是如何進行賦值保存數(shù)據(jù)的。而在 src/core/instance/render.js 的 initRender 方法中則是對 vm.$slots 進行了初始化的賦值。

了解了是 vm.$slots 這塊邏輯后,肯定有人會問:你這不就只是拿到了一個對象么,怎么把其中的內(nèi)容給搞出來呢?別急,我們接著就來講一下對于 slot 這塊 vue 是如何進行編譯的。這里咱就把 slot generate 相關(guān)邏輯過上一過,話不多說,咱直接上代碼

注:上面的 slotName 在 src/compiler/parser/index.js 的 processSlot() 函數(shù)中進行了賦值,并且 父組件編譯階段用到的 slotTarget 也在這里進行了處理

隨即在 genData() 中使用 slotTarget 進行 data 的數(shù)據(jù)拼接

if (el.slotTarget && !el.slotScope) { data += `slot:${el.slotTarget},`}

此時父組件將生成以下代碼

然后當(dāng) el.tag 為 slot 的情況,則直接執(zhí)行 genSlot()

else if (el.tag === 'slot') { return genSlot(el, state)}

按照我們舉出的例子,則子組件最終會生成以下代碼

作用域插槽

上面我們已經(jīng)了解到 vue 對于普通的 slot 標(biāo)簽是如何進行處理和轉(zhuǎn)換的。接下來我們來分析下作用域插槽的實現(xiàn)邏輯。

1、vm.$scopedSlots

了解之前還是老規(guī)矩,先看看 vue 的 Component 接口上對 $scopedSlots 屬性的定義

$scopedSlots: { [key: string]: () => VNodeChildren };

其中的 VNodeChildren 定義如下:

declare type VNodeChildren = Array<?VNode | string | VNodeChildren> | string;

先來個相關(guān)的例子

然后進行使用

效果如下

從使用層面我們能看出來,子組件的 slot 標(biāo)簽上綁定了一個 text 以及 :msg 屬性。然后父組件在使用插槽使用了 slot-scope 屬性去讀取插槽帶的屬性對應(yīng)的值

注:提及一下 processSlot() 對于 slot-scope 的處理邏輯

從上面的代碼我們能看出,vue 對于這塊直接讀取 slot-scope 屬性并賦值給 AST 抽象語法樹的 slotScope 屬性上。而擁有 slotScope 屬性的節(jié)點,會直接以 **插槽名稱 name 為 key、本身為 value **的對象形式掛載在父節(jié)點的 scopedSlots 屬性上

然后在 src/core/instance/render.js 的 renderMixin 方法中對 vm.$scopedSlots 則是進行了如下賦值:

if (_parentVnode) { vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject}

然后 genData() 里會進行以下邏輯處理

if (el.scopedSlots) { data += `${genScopedSlots(el, el.scopedSlots, state)},`}

緊接著我們來看看 genScopedSlots 中的邏輯

然后我們再來看看 genScopedSlot 是如何生成 render function 字符串的

我們把上面例子的 $scopedSlots 打印一下,結(jié)果如下

然后上面例子中父組件最終會生成如下代碼

renderSlot(slot-scope)

上面我們提及對于插槽 render 邏輯的時候忽略了 slot-scope 的相關(guān)邏輯,這里我們來看看這部分內(nèi)容

這里我們看看 renderHelps 里面的 _u ,即 resolveScopedSlots,其邏輯如下

這塊會對 attrs 和 v-bind 進行,對于這塊內(nèi)容上面我已經(jīng)提過了,要看請往上翻閱。結(jié)合我們的例子,子組件則會生成以下代碼

v-slot

1、基本用法

vue 2.6.x 已經(jīng)出來有一段時間了,其中對于插槽這塊則是放棄了 slot-scope 作用域插槽推薦寫法,直接改成了 v-slot 指令形式的推薦寫法(當(dāng)然這只是個語法糖而已)。下面我們將仔細談?wù)?v-slot 這塊的內(nèi)容。

在看具體實現(xiàn)邏輯前,我們先通過一個例子來先了解下其基本用法

然后進行使用

頁面展示效果如下

相同與區(qū)別

接下來,咱來會會這個新特性

round 1. $slots & $scopedSlots

$slots 這塊邏輯沒變,還是沿用的以前的代碼

// $slotsconst options = vm.$optionsconst parentVnode = vm.$vnode = options._parentVnodeconst renderContext = parentVnode && parentVnode.contextvm.$slots = resolveSlots(options._renderChildren, renderContext)

$scopedSlots 這塊則進行了改造,執(zhí)行了 normalizeScopedSlots() 并接收其返回值為 $scopedSlots 的值

接著,我們來會一會 normalizeScopedSlots ,首先我們先看看它的幾個參數(shù)

  • 首先,如果 slots 參數(shù)不存在,則直接返回一個空對象 {}
if (!slots) { res = {}}
  • 若 prevSlots 存在,且滿足系列條件的情況,則直接返回 prevSlots

注:這里的 $key , $hasNormal , $stable 是直接使用 vue 內(nèi)部對 Object.defineProperty 封裝好的 def() 方法進行賦值的

def(res, '$stable', isStable)def(res, '$key', key)def(res, '$hasNormal', hasNormalSlots)復(fù)制代碼
  • 否則,則對 slots 對象進行遍歷,操作 normalSlots ,賦值給 key 為 key,value 為 normalizeScopedSlot 返回的函數(shù) 的對象 res
  • 隨后再次對 normalSlots 進行遍歷,若 normalSlots 中的 key 在 res 找不到對應(yīng)的 key,則直接進行 proxyNormalSlot 代理操作,將 normalSlots 中的 slot 掛載到 res對象上
  • 接著,我們看看 normalizeScopedSlot() 都做了些什么事情。該方法接收三個參數(shù),第一個參數(shù)為 normalSlots,第二個參數(shù)為 key,第三個參數(shù)為 fn

參考文章:

https://juejin.im/post/5cced0096fb9a032426510ad

總結(jié)

以上是生活随笔為你收集整理的slot多作用域 vue_vue 深度长文之slot 篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。