Vue 3.0 & Vue 2.6+ 你需要知道的 v-slot

Vue.js 你需要知道的 v-slot (譯)

面試官:談?wù)?v-slot 的作用?

自己先想一分鐘。

image.png

這篇文章假設(shè)你對(duì)組件的基礎(chǔ)知識(shí)有定義的了解,如果你對(duì)此還不熟悉,請(qǐng)先閱讀。

vue@2.6.x 開(kāi)始,Vue 為具名和范圍插槽引入了一個(gè)全新的語(yǔ)法,即我們今天要講的主角:v-slot 指令。目的就是想統(tǒng)一 slotscope-slot 語(yǔ)法,使代碼更加規(guī)范和清晰。既然有新的語(yǔ)法上位,很明顯,slotscope-slot 也將會(huì)在 vue@3.0.x 中徹底的跟我們說(shuō)拜拜了。而從 vue@2.6.0 開(kāi)始,官方推薦我們使用 v-slot 來(lái)替代后兩者。

我們來(lái)一點(diǎn)一點(diǎn)說(shuō)起吧。文筆有限,不對(duì)之處請(qǐng)留言斧正!

具名插槽

在 2.6.0+ 中已棄用

先前,我們使用具名插槽來(lái)自定義模板內(nèi)容,例如,一個(gè)假設(shè)的 <base-layout> 組件的模板如下:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

在向具名插槽提供內(nèi)容的時(shí)候,我們可以在一個(gè)父組件的 <template> 元素上使用 slot 特性:

<base-layout>
  <template slot="header">
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template slot="footer">
    <p>Here's some contact info</p>
  </template>
</base-layout>

或者直接用在一個(gè)普通的元素上:

<base-layout>
  <h1 slot="header">Here might be a page title</h1>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <p slot="footer">Here's some contact info</p>
</base-layout>

上述兩個(gè)示例渲染出來(lái)的 HTML 都將會(huì)是:

<div class="container">
  <header>
    <h1>Here might be a page title</h1>
  </header>
  <main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </main>
  <footer>
    <p>Here's some contact info</p>
  </footer>
</div>

我們可以使用 v-slot 指令改寫(xiě)上面的栗子:

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

就是這么簡(jiǎn)單,插槽的名字現(xiàn)在通過(guò) v-slot:slotName 這種形式來(lái)使用。

Tips: 沒(méi)有名字的 <slot> 隱含有一個(gè) "default" 名稱

例如,上面的默認(rèn)插槽,如果你想顯示調(diào)用的話,可以這樣:

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

無(wú)論哪種方式,上面的代碼都將輸出為下面代碼:

<div class="container">
  <header>
    <h1>Here might be a page title</h1>
  </header>
  <main>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </main>
  <footer>
    <p>Here's some contact info</p>
  </footer>
</div>

!!!請(qǐng)注意, v-slot 只能添加到 <template> 或自定義組件上,這點(diǎn)與棄用的 slot 屬性不同

作用域插槽

在 2.6.0+ 中已棄用

有時(shí)候,我們想在父組件中訪問(wèn)子組件內(nèi)部的一些可用數(shù)據(jù)。例如,假設(shè)有一個(gè)下面模板的 <current-user> 組件:

<span>
  <slot>{{ user.lastName }}</slot>
</span>

我們可能想用用戶的名字來(lái)替換掉插槽里面的姓,于是我們這樣寫(xiě):

<current-user>
  {{ user.firstName }}
</current-user>

很不幸,上面這段代碼不能如你預(yù)期那樣工作,因?yàn)楫?dāng)前代碼的作用域環(huán)境是在父組件中,所以它訪問(wèn)不了 <current-user> 內(nèi)部的數(shù)據(jù)。

為了解決這個(gè), 我們可以在 <current-user> 內(nèi)部的 <slot> 元素上動(dòng)態(tài)綁定一個(gè) user 對(duì)象屬性:

<span>
  <!-- 完整 v-bind:user 下面是簡(jiǎn)寫(xiě)形式 -->
  <slot :user="user">
    {{ user.lastName }}
  </slot>
</span>

綁定到 <slot> 元素上的屬性我們稱之為 slot props。現(xiàn)在,在父作用域中,我們可以通過(guò) slot-scope 來(lái)訪問(wèn) user 數(shù)據(jù)了:

<current-user>
  <template slot-scope="slotProp">
    {{ slotProp.user.firstName }}
  </template>
</current-user>

同樣的,我們使用 v-slot 重構(gòu)上面的代碼:

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

或者直接作用在 <current-user> 上的寫(xiě)法:

<!-- 省略默認(rèn)插槽名字 -->
<current-user v-slot="slotProp">
  {{ slotProp.user.firstName }}
</current-user>

<!-- 顯示調(diào)用默認(rèn)插槽名字 -->
<current-user v-slot:default="slotProp">
  {{ slotProp.user.firstName }}
</current-user>

在這個(gè)栗子中,我們選擇 slotProp 作為我們的 slot props 名字,但你可以使用你喜歡的任何名字。

單個(gè)默認(rèn)插槽的縮寫(xiě)形式

在上述情況下,當(dāng)且僅當(dāng)提供了默認(rèn)插槽內(nèi)容時(shí),我們可以使用 v-slot 直接作用在組件上:

<current-user v-slot:default="slotProps">
  {{ slotProps.user.firstName }}
</current-user>

我們可以簡(jiǎn)化上面的的默認(rèn)插槽寫(xiě)法:

<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
</current-user>

請(qǐng)注意了,默認(rèn)插槽的縮寫(xiě)語(yǔ)法不能與具名插槽混用:

<!-- 控制臺(tái)將報(bào)警告:-->
<!-- To avoid scope ambiguity, the default slot should also use <template> syntax when there are other named slots. -->
<!-- 意思就是說(shuō),為了避免作用域模糊 -->
<!-- 當(dāng)有其他具名插槽時(shí),默認(rèn)插槽也應(yīng)當(dāng)使用 '<template>' 模板語(yǔ)法 -->
<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
  <template v-slot:other="otherSlotProps">
    slotProps is NOT available here
  </template>
</current-user>

于是,上面的代碼,我們改寫(xiě)成:

<current-user>
 <!-- 兩種寫(xiě)法均可 -->
  <!--<template v-slot="slotProps">
    {{ slotProps.user.firstName }}
  </template>-->
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</current-user>

插槽內(nèi)容的解構(gòu)賦值

在 Vue 代碼內(nèi)部,我們傳遞的 slotProps 其實(shí)就是函數(shù)的一個(gè)單一參數(shù):

function (slotProps) {
  // ... slot content ...
}

這也就意味著 v-slot 的值只要滿足函數(shù)參數(shù)定義的 JavaScript 表達(dá)式的都可以接受。因此,在支持的環(huán)境(單文件或現(xiàn)代瀏覽器)中,你還可以使用 ES2015 解構(gòu)語(yǔ)法來(lái)提取特定的插值內(nèi)容,例如:

<current-user v-slot="{ user }">
  {{ user.firstName }}
</current-user>

代碼看起來(lái)更簡(jiǎn)潔對(duì)吧。我們還可以重命名解構(gòu)變量:

<current-user v-slot="{ user: person }">>
  {{ person.firstName }}
</current-user>

這給了我們很多自由操作的空間,你甚至可以自定義回退內(nèi)容,以便在未定義插值情況下使用:

<current-user v-slot="{ user = { firstName: 'Guest' } }">>
  {{ user.firstName }}
</current-user>

動(dòng)態(tài)插槽名稱

2.6.0+ 新增

動(dòng)態(tài)指令參數(shù) 也適用于 v-slot ,允許我們定義動(dòng)態(tài)插槽名稱:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>

命名插槽簡(jiǎn)寫(xiě)

2.6.0+ 新增

v-onv-bind 類(lèi)似,v-slot 也有一個(gè)簡(jiǎn)寫(xiě),即使用 # 代替 v-slot。例如, v-slot:header 簡(jiǎn)寫(xiě)成 #header:

<base-layout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

和其他指令一樣,只有在提供參數(shù)時(shí)才能使用簡(jiǎn)寫(xiě)形式,下面的寫(xiě)法是無(wú)效的:

<!-- 將會(huì)觸發(fā)一個(gè)控制臺(tái)警告 -->
<current-user #="{ user }">
  {{ user.firstName }}
</current-user>

也就是說(shuō),如果你想使用簡(jiǎn)寫(xiě)語(yǔ)法,則務(wù)必指定插值的名字:

<current-user #default="{ user }">
  {{ user.firstName }}
</current-user>

參考

結(jié)語(yǔ)

看了那么多 相信也有同學(xué)和我一樣有點(diǎn)暈...(應(yīng)該只有我有點(diǎn)暈)
我們先要捋清楚思路2個(gè)概念
1.父組件要插入子組件的具名插槽(slot)
2.父組件需要用到子組件的數(shù)據(jù) (怎么玩看你)
我們先來(lái)看第一個(gè)

1
//父組件
<child>
  <template v-slot:header> 我是父組件插入子組件了</template>
  ??????也可以簡(jiǎn)寫(xiě)
  <template #header> 我是父組件插入子組件了</template>
</child>
//子組件
<template>
  <div>
  <slot name ="header">我是子組件原來(lái)的數(shù)據(jù)</slot>
  </div>
</template>

以上的代碼是父組件插入子組件的插槽

2
//父組件
<child v-slot="slotProp">
  <template v-slot:header> {{slotProp.name}}</template>
</child>
//子組件
<template>
  <div>
  <slot name ="header" :slotProp="{name: '我是傳出去的數(shù)據(jù)'}">我是子組件原來(lái)的數(shù)據(jù)</slot>
  </div>
</template>

這樣我們就是把"我是傳出去的數(shù)據(jù)"插入到了子組件的數(shù)據(jù)

注意區(qū)別對(duì)待v-slot="" 和v-slot:name

=和:的區(qū)別 一個(gè)是slot的name 一個(gè)是父組件獲取子組件的數(shù)據(jù)

以下還有個(gè)代碼片段僅供參考
代碼片段

項(xiàng)目使用element-Ui的 請(qǐng)不要升級(jí)2.6+ 詳情見(jiàn)圖片


注意事項(xiàng).png

文章轉(zhuǎn)自掘金gongph

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容