W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
該頁(yè)面假設(shè)你已經(jīng)閱讀過(guò)了組件基礎(chǔ)。如果你還對(duì)組件不太了解,推薦你先閱讀它。
Vue 實(shí)現(xiàn)了一套內(nèi)容分發(fā)的 API,這套 API 的設(shè)計(jì)靈感源自 Web Components 規(guī)范草案,將 <slot>
元素作為承載分發(fā)內(nèi)容的出口。
它允許你像這樣合成組件:
<todo-button>
Add todo
</todo-button>
然后在 <todo-button>
的模板中,你可能有:
<!-- todo-button 組件模板 -->
<button class="btn-primary">
<slot></slot>
</button>
當(dāng)組件渲染的時(shí)候,將會(huì)被替換為“Add Todo”。
<!-- 渲染 HTML -->
<button class="btn-primary">
Add todo
</button>
不過(guò),字符串只是開始!插槽還可以包含任何模板代碼,包括 HTML:
<todo-button>
<!-- 添加一個(gè)Font Awesome 圖標(biāo) -->
<i class="fas fa-plus"></i>
Add todo
</todo-button>
或其他組件
<todo-button>
<!-- 添加一個(gè)圖標(biāo)的組件 -->
<font-awesome-icon name="plus"></font-awesome-icon>
Add todo
</todo-button>
如果 <todo-button>
的 template 中沒(méi)有包含一個(gè) <slot>
元素,則該組件起始標(biāo)簽和結(jié)束標(biāo)簽之間的任何內(nèi)容都會(huì)被拋棄
<!-- todo-button 組件模板 -->
<button class="btn-primary">
Create a new item
</button>
<todo-button>
<!-- 以下文本不會(huì)渲染 -->
Add todo
</todo-button>
當(dāng)你想在一個(gè)插槽中使用數(shù)據(jù)時(shí),例如:
<todo-button>
Delete a {{ item.name }}
</todo-button>
該插槽可以訪問(wèn)與模板其余部分相同的實(shí)例 property (即相同的“作用域”)。
插槽不能訪問(wèn) <todo-button>
的作用域。例如,嘗試訪問(wèn) action
將不起作用:
<todo-button action="delete">
Clicking here will {{ action }} an item
<!-- `action` 未被定義,因?yàn)樗膬?nèi)容是傳遞*到* <todo-button>,而不是*在* <todo-button>里定義的。 -->
</todo-button>
作為一條規(guī)則,請(qǐng)記?。?/p>
父級(jí)模板里的所有內(nèi)容都是在父級(jí)作用域中編譯的;子模板里的所有內(nèi)容都是在子作用域中編譯的。
有時(shí)為一個(gè)插槽設(shè)置具體的后備 (也就是默認(rèn)的) 內(nèi)容是很有用的,它只會(huì)在沒(méi)有提供內(nèi)容的時(shí)候被渲染。例如在一個(gè) <submit-button>
組件中:
<button type="submit">
<slot></slot>
</button>
我們可能希望這個(gè) <button>
內(nèi)絕大多數(shù)情況下都渲染文本“Submit”。為了將“Submit”作為后備內(nèi)容,我們可以將它放在 <slot>
標(biāo)簽內(nèi):
<button type="submit">
<slot>Submit</slot>
</button>
現(xiàn)在當(dāng)我在一個(gè)父級(jí)組件中使用 <submit-button
> 并且不提供任何插槽內(nèi)容時(shí):
<submit-button></submit-button>
后備內(nèi)容“Submit”將會(huì)被渲染:
<button type="submit">
Submit
</button>
但是如果我們提供內(nèi)容:
<submit-button>
Save
</submit-button>
則這個(gè)提供的內(nèi)容將會(huì)被渲染從而取代后備內(nèi)容:
<button type="submit">
Save
</button>
有時(shí)我們需要多個(gè)插槽。例如對(duì)于一個(gè)帶有如下模板的 <base-layout>
組件:
<div class="container">
<header>
<!-- 我們希望把頁(yè)頭放這里 -->
</header>
<main>
<!-- 我們希望把主要內(nèi)容放這里 -->
</main>
<footer>
<!-- 我們希望把頁(yè)腳放這里 -->
</footer>
</div>
對(duì)于這樣的情況,<slot>
元素有一個(gè)特殊的 attribute:name
。這個(gè) attribute 可以用來(lái)定義額外的插槽:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
一個(gè)不帶 name
的 <slot>
出口會(huì)帶有隱含的名字“default”。
在向具名插槽提供內(nèi)容的時(shí)候,我們可以在一個(gè) <template>
元素上使用 v-slot
指令,并以 v-slot
的參數(shù)的形式提供其名稱:
<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>
現(xiàn)在 <template>
元素中的所有內(nèi)容都將會(huì)被傳入相應(yīng)的插槽。
渲染的 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
只能添加在 <template>
上 (只有一種例外情況)
有時(shí)讓插槽內(nèi)容能夠訪問(wèn)子組件中才有的數(shù)據(jù)是很有用的。當(dāng)一個(gè)組件被用來(lái)渲染一個(gè)項(xiàng)目數(shù)組時(shí),這是一個(gè)常見的情況,我們希望能夠自定義每個(gè)項(xiàng)目的渲染方式。
例如,我們有一個(gè)組件,包含 todo-items 的列表。
app.component('todo-list', {
data() {
return {
items: ['Feed a cat', 'Buy milk']
}
},
template: `
<ul>
<li v-for="(item, index) in items">
{{ item }}
</li>
</ul>
`
})
我們可能需要替換插槽以在父組件上自定義它:
<todo-list>
<i class="fas fa-check"></i>
<span class="green">{{ item }}</span>
</todo-list>
但是,這是行不通的,因?yàn)橹挥?<todo-list>
組件可以訪問(wèn) item
,我們將從其父組件提供槽內(nèi)容。
要使 item
可用于父級(jí)提供的 slot 內(nèi)容,我們可以添加一個(gè) <slot>
元素并將其綁定為屬性:
<ul>
<li v-for="( item, index ) in items">
<slot :item="item"></slot>
</li>
</ul>
綁定在 <slot
> 元素上的 attribute 被稱為插槽 prop?,F(xiàn)在在父級(jí)作用域中,我們可以使用帶值的 v-slot
來(lái)定義我們提供的插槽 prop 的名字:
<todo-list>
<template v-slot:default="slotProps">
<i class="fas fa-check"></i>
<span class="green">{{ slotProps.item }}</span>
</template>
</todo-list>
在這個(gè)例子中,我們選擇將包含所有插槽 prop 的對(duì)象命名為 slotProps
,但你也可以使用任意你喜歡的名字。
在上述情況下,當(dāng)被提供的內(nèi)容只有默認(rèn)插槽時(shí),組件的標(biāo)簽才可以被當(dāng)作插槽的模板來(lái)使用。這樣我們就可以把 v-slot
直接用在組件上:
<todo-list v-slot:default="slotProps">
<i class="fas fa-check"></i>
<span class="green">{{ slotProps.item }}</span>
</todo-list>
這種寫法還可以更簡(jiǎn)單。就像假定未指明的內(nèi)容對(duì)應(yīng)默認(rèn)插槽一樣,不帶參數(shù)的 v-slot
被假定對(duì)應(yīng)默認(rèn)插槽:
<todo-list v-slot="slotProps">
<i class="fas fa-check"></i>
<span class="green">{{ slotProps.item }}</span>
</todo-list>
注意默認(rèn)插槽的縮寫語(yǔ)法不能和具名插槽混用,因?yàn)樗鼤?huì)導(dǎo)致作用域不明確:
<!-- 無(wú)效,會(huì)導(dǎo)致警告 -->
<todo-list v-slot="slotProps">
<todo-list v-slot:default="slotProps">
<i class="fas fa-check"></i>
<span class="green">{{ slotProps.item }}</span>
</todo-list>
<template v-slot:other="otherSlotProps">
slotProps is NOT available here
</template>
</todo-list>
只要出現(xiàn)多個(gè)插槽,請(qǐng)始終為所有的插槽使用完整的基于 <template>
的語(yǔ)法:
<todo-list>
<template v-slot:default="slotProps">
<i class="fas fa-check"></i>
<span class="green">{{ slotProps.item }}</span>
</template>
<template v-slot:other="otherSlotProps">
...
</template>
</todo-list>
作用域插槽的內(nèi)部工作原理是將你的插槽內(nèi)容包括在一個(gè)傳入單個(gè)參數(shù)的函數(shù)里:
function (slotProps) {
// ... 插槽內(nèi)容 ...
}
這意味著 v-slot
的值實(shí)際上可以是任何能夠作為函數(shù)定義中的參數(shù)的 JavaScript 表達(dá)式。你也可以使用 ES2015 解構(gòu)來(lái)傳入具體的插槽 prop,如下:
<todo-list v-slot="{ item }">
<i class="fas fa-check"></i>
<span class="green">{{ item }}</span>
</todo-list>
這樣可以使模板更簡(jiǎn)潔,尤其是在該插槽提供了多個(gè) prop 的時(shí)候。它同樣開啟了 prop 重命名等其它可能,例如將 item
重命名為 todo
:
<todo-list v-slot="{ item: todo }">
<i class="fas fa-check"></i>
<span class="green">{{ todo }}</span>
</todo-list>
你甚至可以定義后備內(nèi)容,用于插槽 prop 是 undefined 的情形:
<todo-list v-slot="{ item = 'Placeholder' }">
<i class="fas fa-check"></i>
<span class="green">{{ item }}</span>
</todo-list>
動(dòng)態(tài)指令參數(shù)也可以用在 v-slot
上,來(lái)定義動(dòng)態(tài)的插槽名:
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
</base-layout>
跟 v-on
和 v-bind
一樣,v-slot
也有縮寫,即把參數(shù)之前的所有內(nèi)容 (v-slot:
) 替換為字符 #
。例如 v-slot:header
可以被重寫為 #header
:
<base-layout>
<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>
</base-layout>
然而,和其它指令一樣,該縮寫只在其有參數(shù)的時(shí)候才可用。這意味著以下語(yǔ)法是無(wú)效的:
<!-- This will trigger a warning -->
<todo-list #="{ item }">
<i class="fas fa-check"></i>
<span class="green">{{ item }}</span>
</todo-list>
如果你希望使用縮寫的話,你必須始終以明確插槽名取而代之:
<todo-list #default="{ item }">
<i class="fas fa-check"></i>
<span class="green">{{ item }}</span>
</todo-list>
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: