1. 具名插槽
1.1 沒(méi)有使用具名插槽的問(wèn)題
有的時(shí)候我們?cè)谑褂米咏M件時(shí),在子組件模板上不同的位置插入不同的內(nèi)容, 只有一個(gè)插槽顯然沒(méi)發(fā)滿足我們的需求,看示例:
需求如下:
- 子組件是一篇文章的結(jié)構(gòu)
- 父組件在調(diào)用子組件是給文章插入標(biāo)題,正文,時(shí)間信息
示例代碼如下:
<div id="app">
<!-- 使用組件 -->
<my-child >
<h2>這是一篇介紹vue插槽的文章</h2>
<p>這是文章的第一段</p>
<p>這是文章的第二段內(nèi)容</p>
<p>這是文章的第三段內(nèi)容</p>
<span>2020年5月1日</span>
</my-child>
</div>
<!-- 組件模板 -->
<template id="mychild">
<div class="article">
<div class="title">
<slot></slot>
</div>
<div class="contont">
<slot></slot>
</div>
<div class="time">
<slot></slot>
</div>
</div>
</template>
<script>
// 組件選項(xiàng)對(duì)象
let MyChild = {
template: `#mychild`
};
// 實(shí)例中注冊(cè)組件
const vm = new Vue({
el:"#app",
components: {
MyChild
}
})
</script>
結(jié)果:

示例結(jié)果說(shuō)明:
- 通過(guò)示例結(jié)果發(fā)現(xiàn)和我們想的天差地別,此時(shí)每一個(gè)插槽都插入了所有的內(nèi)容, 顯然不符合預(yù)期
- 那么我們?cè)鯓硬拍軐⒎职l(fā)的內(nèi)容指定到每一個(gè)具體的插槽上呢.
這個(gè)時(shí)候我們就需要給每個(gè)插槽指定名字
1.2 使用具名插槽和默認(rèn)插槽
<slot> 元素可以用一個(gè)特殊的特性 name 來(lái)進(jìn)一步配置如何分發(fā)內(nèi)容。多個(gè)插槽可以有不同的名字。具名插槽將匹配內(nèi)容片段中有對(duì)應(yīng) slot 特性的元素。
未使用name屬性的slot插槽被稱匿名插槽, 也可以叫做默認(rèn)插槽. 我們?cè)谧咏M件中仍然可以有一個(gè)匿名插槽,作為找不到匹配的內(nèi)容片段的備用插槽。如果沒(méi)有默認(rèn)插槽,這些找不到匹配的內(nèi)容片段將被拋棄。
使用具名操作重寫上面的示例:
<div id="app">
<!-- 使用組件 -->
<my-child >
<h2 slot="title">這是一篇介紹vue插槽的文章</h2>
<p>這是文章的第一段</p>
<p>這是文章的第二段內(nèi)容</p>
<p>這是文章的第三段內(nèi)容</p>
<span slot="time">2020年5月1日</span>
</my-child>
</div>
<!-- 組件模板 -->
<template id="mychild">
<div class="article">
<div class="title">
<slot name="title">這里是標(biāo)題內(nèi)容的插槽</slot>
</div>
<div class="contont">
<slot>這里是默認(rèn)插槽</slot>
</div>
<div class="time">
<slot name="time">這里是時(shí)間的插槽</slot>
</div>
</div>
</template>
<script>
// 組件選項(xiàng)對(duì)象
let MyChild = {
template: `#mychild`
};
// 實(shí)例中注冊(cè)組件
const vm = new Vue({
el:"#app",
components: {
MyChild
}
})
</script>
結(jié)果:

此時(shí)我們就會(huì)發(fā)現(xiàn),分發(fā)的內(nèi)容以及正常插入到對(duì)應(yīng)的插槽上了
通過(guò)上面的例子我們就知道了,slot如果沒(méi)有顯示的使用name屬性指定插槽的名字,那么slot默認(rèn)有個(gè)名字default,默認(rèn)插槽,如果在分發(fā)內(nèi)容時(shí),沒(méi)有指定插槽,所有的內(nèi)容都將默認(rèn)插到默認(rèn)插槽上
2. 作用域插槽
2.1 作用插槽的理解和使用
通過(guò)學(xué)習(xí)我們知道,插槽的內(nèi)容最后是在子組件模板上渲染的, 那么就會(huì)在有得時(shí)候需要在分發(fā)的內(nèi)容中使用子組件中才有的數(shù)據(jù),怎么辦呢. 這個(gè)時(shí)候就要用到作用域插槽了
作用域插槽是一種特殊類型的插槽,用作一個(gè) (能被傳遞數(shù)據(jù)的) 可重用模板,來(lái)代替已經(jīng)渲染好的元素。
簡(jiǎn)而言之,就是利用slot 標(biāo)簽將子組件的數(shù)據(jù)傳遞到分發(fā)內(nèi)中上,就像prop傳遞數(shù)據(jù)給組件一樣
在父級(jí)中,具有特殊特性 slot-scope 的 <template> 元素必須存在,表示它是作用域插槽的模板。slot-scope 的值將被用作一個(gè)臨時(shí)變量名,此變量接收從子組件傳遞過(guò)來(lái)的 props 對(duì)象:
示例:
<div id="app">
<!-- 使用組件 -->
<my-child >
<template slot-scope="props">
<button>{{ props.text }}</button>
</template>
</my-child>
</div>
<!-- 組件模板 -->
<template id="mychild">
<div>
<slot :text="text"></slot>
</div>
</template>
<script>
// 組件選項(xiàng)對(duì)象
let MyChild = {
template: `#mychild`,
data(){
return {
text: "提交"
}
}
};
// 實(shí)例中注冊(cè)組件
const vm = new Vue({
el:"#app",
components: {
MyChild
}
})
</script>
在 2.5.0+,
slot-scope能被用在任意元素或組件中而不再局限于<template>。
也就意味著可以如下寫法
<div id="app">
<!-- 使用組件 -->
<my-child >
<button slot-scope="props">{{ props.text }}</button>
</my-child>
</div>
顯示結(jié)果

2.2 作用域插槽也可以使用解構(gòu)寫法
<div id="app">
<!-- 使用組件 -->
<my-child >
<button slot-scope="{text}">{{ text }}</button>
</my-child>
</div>
很遺憾的告訴你, 具名插槽和作用域插槽的用法在未來(lái)即將被廢棄?
What? 那么我們?cè)趺刺幚砭呙宀酆妥饔糜虿宀廴∠罅粝碌膯?wèn)題呢? 不用擔(dān)心,往下看.
3. v-slot指令
v-slot指令自 Vue 2.6.0 起被引入,提供更好的支持slot和slot-scopeattribute 的 API 替代方案。v-slot完整的由來(lái)參見這份 RFC。在接下來(lái)所有的 2.x 版本中slot和slot-scopeattribute 仍會(huì)被支持,但已經(jīng)被官方廢棄且不會(huì)出現(xiàn)在 Vue 3 中。
3.1 使用v-slot處理具名插槽的問(wèn)題
在向具名插槽提供內(nèi)容的時(shí)候,我們可以在一個(gè) <template> 元素上使用 v-slot 指令,并以 v-slot 的參數(shù)的形式提供其名稱:
<div id="app">
<!-- 使用組件 -->
<my-child >
<template v-slot:title>
<h2>這是一篇介紹vue插槽的文章</h2>
</template>
<p>這是文章的第一段</p>
<p>這是文章的第二段內(nèi)容</p>
<p>這是文章的第三段內(nèi)容</p>
<template v-slot:time>
<span>2020年5月1日</span>
</template>
</my-child>
</div>
<!-- 組件模板 -->
<template id="mychild">
<div class="article">
<div class="title">
<slot name="title">這里是標(biāo)題內(nèi)容的插槽</slot>
</div>
<div class="contont">
<slot>這里是默認(rèn)插槽</slot>
</div>
<div class="time">
<slot name="time">這里是時(shí)間的插槽</slot>
</div>
</div>
</template>
<script>
// 組件選項(xiàng)對(duì)象
let MyChild = {
template: `#mychild`
};
// 實(shí)例中注冊(cè)組件
const vm = new Vue({
el:"#app",
components: {
MyChild
}
})
</script>
顯示結(jié)果:

現(xiàn)在 <template> 元素中的所有內(nèi)容都將會(huì)被傳入相應(yīng)的插槽。任何沒(méi)有被包裹在帶有 v-slot 的 <template> 中的內(nèi)容都會(huì)被視為默認(rèn)插槽的內(nèi)容。
如果你希望更明確一些,仍然可以在一個(gè) <template> 中包裹默認(rèn)插槽的內(nèi)容:
<div id="app">
<!-- 使用組件 -->
<my-child >
<template v-slot:title>
<h2>這是一篇介紹vue插槽的文章</h2>
</template>
<template v-slot:default>
<p>這是文章的第一段</p>
<p>這是文章的第二段內(nèi)容</p>
<p>這是文章的第三段內(nèi)容</p>
</template>
<template v-slot:time>
<span>2020年5月1日</span>
</template>
</my-child>
</div>
注意 v-slot 只能添加在 <template> 上
3.2 使用v-slot處理作用域插槽的問(wèn)題
綁定在 <slot> 元素上的 attribute 被稱為插槽 prop?,F(xiàn)在在父級(jí)作用域中,我們可以使用帶值的 v-slot 來(lái)定義我們提供的插槽 prop 的名字:
<div id="app">
<!-- 使用組件 -->
<my-child >
<template v-slot:default="props">
<button>{{ props.text }}</button>
</template>
</my-child>
</div>
<!-- 組件模板 -->
<template id="mychild">
<div>
<slot :text="text"></slot>
</div>
</template>
<script>
// 組件選項(xiàng)對(duì)象
let MyChild = {
template: `#mychild`,
data(){
return {
text: "提交"
}
}
};
// 實(shí)例中注冊(cè)組件
const vm = new Vue({
el:"#app",
components: {
MyChild
}
})
</script>
顯示結(jié)果

3.3 作用域插槽的特殊處理
在上述情況下,當(dāng)被提供的內(nèi)容只有默認(rèn)插槽時(shí),組件的標(biāo)簽才可以被當(dāng)作插槽的模板來(lái)使用。這樣我們就可以把 v-slot 直接用在組件上:
<div id="app">
<!-- 使用組件 -->
<my-child v-slot:default="props">
<button>{{ props.text }}</button>
</my-child>
</div>
這種寫法還可以更簡(jiǎn)單。就像假定未指明的內(nèi)容對(duì)應(yīng)默認(rèn)插槽一樣,不帶參數(shù)的 v-slot 被假定對(duì)應(yīng)默認(rèn)插槽:
<div id="app">
<!-- 使用組件 -->
<my-child v-slot="props">
<button>{{ props.text }}</button>
</my-child>
</div>
這用這種簡(jiǎn)單語(yǔ)法的情況就是在組件中只有一個(gè)默認(rèn)插槽,一但有多個(gè)插槽,請(qǐng)使用完整的語(yǔ)法
4. 動(dòng)態(tài)插槽
2.6.0 新增
動(dòng)態(tài)指令參數(shù)也可以用在 v-slot 上,來(lái)定義動(dòng)態(tài)的插槽名:
還是以我們剛才文章的那個(gè)多插槽為例;
<div id="app">
<!-- 使用組件 -->
<my-child >
<template v-slot:[head]>
<h2>這是一篇介紹vue插槽的文章</h2>
</template>
<p>這是文章的第一段</p>
<p>這是文章的第二段內(nèi)容</p>
<p>這是文章的第三段內(nèi)容</p>
<template v-slot:[food]>
<span>2020年5月1日</span>
</template>
</my-child>
</div>
<!-- 組件模板 -->
<template id="mychild">
<div class="article">
<div class="title">
<slot name="title">這里是標(biāo)題內(nèi)容的插槽</slot>
</div>
<div class="contont">
<slot>這里是默認(rèn)插槽</slot>
</div>
<div class="time">
<slot name="time">這里是時(shí)間的插槽</slot>
</div>
</div>
</template>
<script>
// 組件選項(xiàng)對(duì)象
let MyChild = {
template: `#mychild`
};
// 實(shí)例中注冊(cè)組件
const vm = new Vue({
el:"#app",
data:{
head:"title",
food:"time"
},
components: {
MyChild
}
})
</script>
此時(shí)template 標(biāo)簽上的v-solt指令參數(shù)是一個(gè)中括號(hào), 中括號(hào)里的值將是一個(gè)變量,為當(dāng)前父組件的數(shù)據(jù)
5. 具名插槽的縮寫
2.6.0 新增
跟 v-on 和 v-bind 一樣,v-slot 也有縮寫,即把參數(shù)之前的所有內(nèi)容 (v-slot:) 替換為字符 #。例如 v-slot:header 可以被重寫為 #header:
<div id="app">
<!-- 使用組件 -->
<my-child >
<template #title>
<h2>這是一篇介紹vue插槽的文章</h2>
</template>
<p>這是文章的第一段</p>
<p>這是文章的第二段內(nèi)容</p>
<p>這是文章的第三段內(nèi)容</p>
<template #time>
<span>2020年5月1日</span>
</template>
</my-child>
</div>
然而,和其它指令一樣,該縮寫只在其有參數(shù)的時(shí)候才可用。這意味著以下語(yǔ)法是無(wú)效的:
<my-child >
<!-- 這種寫法無(wú)效 -->
<template #="props">
<h2>這是一篇介紹vue插槽的文章</h2>
</template>
</my-child>
如果你希望使用縮寫的話,你必須始終以明確插槽名取而代之:
<my-child >
<!-- 這種寫法有效,因?yàn)橛兄噶顓?shù) -->
<template #deatule="props">
<h2>這是一篇介紹vue插槽的文章</h2>
</template>
</my-child>