數(shù)字化管理平臺(tái)
Vue3+Vite+VueRouter+Pinia+Axios+ElementPlus
權(quán)限系統(tǒng)-商城
個(gè)人博客地址
概述
在某些場(chǎng)景中,我們可能想要為子組件傳遞一些模板片段,讓子組件在它們的組件中渲染這些片段。這就用到了插槽。
插槽是子組件中的提供給父組件使用的一個(gè)占位符,用 <slot>
表示,父組件可以在這個(gè)占位符中填充任何模板代碼,如 HTML、組件等,填充的內(nèi)容會(huì)替換子組件的<slot>
元素。<slot>
元素是一個(gè)插槽出口 (slot outlet),標(biāo)示了父元素提供的插槽內(nèi)容 (slot content) 將在哪里被渲染。
一、匿名插槽
子組件 FancyButton 中插槽模板
# 基礎(chǔ)用法
<button class="fancy-btn">
<!-- 插槽出口 -->
<slot></slot>
</button>
# 可指定默認(rèn)插槽內(nèi)容:父組件沒(méi)有提供任何插槽內(nèi)容時(shí),默認(rèn)渲染的插槽內(nèi)容 Submit
<button class="fancy-btn">
<slot>Submit</slot>
</button>
父組件填充插槽內(nèi)容
<FancyButton>
<!-- 插槽內(nèi)容 -->
<div>Click me!</div>
</FancyButton>
# 或
<FancyButton>
<!-- 插槽內(nèi)容 -->
<template v-slot>
<div>Click Me</div>
</template>
</FancyButton>
最終渲染出的 DOM 結(jié)構(gòu)如下
<button class="fancy-btn">Click me!</button>
通過(guò)使用插槽,使組件更加靈活和具有可復(fù)用性。這樣組件可以用在不同的地方渲染各異的內(nèi)容,但同時(shí)還保證都具有相同的樣式。
二、具名插槽 (named slots)
具名插槽其實(shí)就是給插槽取個(gè)名字。一個(gè)子組件可以放多個(gè)插槽,而且可以放在不同的地方,而父組件填充內(nèi)容時(shí),可以根據(jù)這個(gè)名字把內(nèi)容填充到對(duì)應(yīng)插槽中。
對(duì)于這種場(chǎng)景,<slot>
元素可以有一個(gè)特殊的屬性 name
,用來(lái)給各個(gè)插槽分配唯一的 ID,以確定每一處要渲染的內(nèi)容:
-
子組件預(yù)留的插槽
<div class="container"> <header> <slot name="header"></slot> </header> <main> <-- 沒(méi)有提供 name 的 slot 出口會(huì)隱式地命名為 “default” --> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
-
父組件對(duì)指定插槽進(jìn)行填充
要為具名插槽傳入內(nèi)容,我們需要使用一個(gè)含
v-slot
指令的<template>
元素,并將目標(biāo)插槽的名字傳給該指令。<BaseLayout> <template v-slot:header> <div>header</div> </template> <template v-slot> <div>default</div> </template> <template v-slot:footer> <div>footer</div> </template> </BaseLayout>
-
v-slot 語(yǔ)法糖(簡(jiǎn)寫方式)
v-slot
有對(duì)應(yīng)的簡(jiǎn)寫#
,因此<template v-slot:header>
可以簡(jiǎn)寫為<template #header>
。其意思就是“將這部分模板片段傳入子組件的 header 插槽中”。
<BaseLayout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<template #default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
# 或
# 當(dāng)一個(gè)組件同時(shí)接收默認(rèn)插槽和具名插槽時(shí),所有位于頂級(jí)的非 <template> 節(jié)點(diǎn)都被隱式地視為默認(rèn)插槽的內(nèi)容。所以上面也可以寫成:
<BaseLayout>
<template #header>
<h1>Here might be a page title</h1>
</template>
<!-- 隱式的默認(rèn)插槽 -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
現(xiàn)在 <template>
元素中的所有內(nèi)容都將被傳遞到相應(yīng)的插槽。最終渲染出的 HTML 如下:
<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>
三、動(dòng)態(tài)插槽
動(dòng)態(tài)指令參數(shù)在 v-slot
上也是有效的,即可以通過(guò)變量定義動(dòng)態(tài)插槽名:
<script setup>
import { ref } from "vue";
const name = ref('header')
</script>
<template>
<base-layout>
<template v-slot:[name]>
<div>動(dòng)態(tài)插槽</div>
</template>
<!-- 縮寫為 -->
<template #[name]>
<div>動(dòng)態(tài)插槽</div>
</template>
</base-layout>
</temppate>
四、作用域插槽
在某些場(chǎng)景下插槽的內(nèi)容可能想要同時(shí)使用父組件域內(nèi)和子組件域內(nèi)的數(shù)據(jù)??梢允褂脤傩越壎ǖ姆绞较蛞粋€(gè)插槽的出口上傳遞數(shù)據(jù),稱為插槽 props 。
4.1 匿名插槽數(shù)據(jù)傳遞
子組件 MyComponent
傳遞插槽 props
<div>
<slot :text="greetingMessage" :count="1"></slot>
</div>
父組件接收插槽 props:默認(rèn)插槽通過(guò)子組件標(biāo)簽上的 v-slot
指令,直接接收到了一個(gè)插槽 props 對(duì)象
<MyComponent v-slot="slotProps">
{{ slotProps.text }} {{ slotProps.count }}
</MyComponent>
# 或 在 v-slot 中使用解構(gòu)語(yǔ)法
<MyComponent v-slot="{ text, count }">
{{ text }} {{ count }}
</MyComponent>
4.2 具名插槽數(shù)據(jù)傳遞
具名作用域插槽的工作方式也是類似的,插槽 props 可以作為 v-slot
指令的值被訪問(wèn)到:v-slot:name="slotProps"
。
<slot name="header" message="hello"></slot>
<MyComponent>
<template #header="headerProps">
{{ headerProps }}
</template>
<template #default="defaultProps">
{{ defaultProps }}
</template>
<template #footer="footerProps">
{{ footerProps }}
</template>
</MyComponent>
4.3 作用域插槽應(yīng)用場(chǎng)景:高級(jí)列表組件示例
你可能想問(wèn)什么樣的場(chǎng)景才適合用到作用域插槽,這里我們來(lái)看一個(gè) <FancyList>
組件的例子。它會(huì)渲染一個(gè)列表,并同時(shí)會(huì)封裝一些加載遠(yuǎn)端數(shù)據(jù)的邏輯、使用數(shù)據(jù)進(jìn)行列表渲染、或者是像分頁(yè)或無(wú)限滾動(dòng)這樣更進(jìn)階的功能。然而我們希望它能夠保留足夠的靈活性,將對(duì)單個(gè)列表元素內(nèi)容和樣式的控制權(quán)留給使用它的父組件。我們期望的用法可能是這樣的:
<FancyList :api-url="url" :per-page="10">
<template #item="{ body, username, likes }">
<div class="item">
<p>{{ body }}</p>
<p>by {{ username }} | {{ likes }} likes</p>
</div>
</template>
</FancyList>
在 <FancyList>
之中,我們可以多次渲染 <slot>
并每次都提供不同的數(shù)據(jù) (注意我們這里使用了 v-bind
來(lái)傳遞插槽的 props):
<ul>
<li v-for="item in items">
<slot name="item" v-bind="item"></slot>
</li>
</ul>
上面的 <FancyList>
案例同時(shí)封裝了可重用的邏輯 (數(shù)據(jù)獲取、分頁(yè)等) 和視圖輸出,但也將部分視圖輸出通過(guò)作用域插槽交給了消費(fèi)者組件來(lái)管理。
如果我們將這個(gè)概念拓展一下,可以想象的是,一些組件可能只包括了邏輯而不需要自己渲染內(nèi)容,視圖輸出通過(guò)作用域插槽全權(quán)交給了消費(fèi)者組件。我們將這種類型的組件稱為無(wú)渲染組件。
這里有一個(gè)無(wú)渲染組件的例子,一個(gè)封裝了追蹤當(dāng)前鼠標(biāo)位置邏輯的組件:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-700304.html
<MouseTracker v-slot="{ x, y }">
Mouse is at: {{ x }}, {{ y }}
</MouseTracker>
雖然這個(gè)模式很有趣,但大部分能用無(wú)渲染組件實(shí)現(xiàn)的功能都可以通過(guò)組合式 API 以另一種更高效的方式實(shí)現(xiàn),并且還不會(huì)帶來(lái)額外組件嵌套的開(kāi)銷。
盡管如此,作用域插槽在需要同時(shí)封裝邏輯、組合視圖界面時(shí)還是很有用,就像上面的 <FancyList>
組件那樣。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-700304.html
到了這里,關(guān)于【Vue3 第十九章】插槽 slot的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!