1. 具名插槽
1.1 沒有使用具名插槽的問題
有的時(shí)候我們在使用子組件時(shí),在子組件模板上不同的位置插入不同的內(nèi)容, 只有一個(gè)插槽顯然沒法滿足我們的需求,看示例:
需求如下:
- 子組件是一篇文章的結(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)對象
let MyChild = {
template: `#mychild`
};
// 實(shí)例中注冊組件
const vm = new Vue({
el:"#app",
components: {
MyChild
}
})
</script>
結(jié)果:
示例結(jié)果說明:
- 通過示例結(jié)果發(fā)現(xiàn)和我們想的天差地別,此時(shí)每一個(gè)插槽都插入了所有的內(nèi)容, 顯然不符合預(yù)期
- 那么我們怎樣才能將分發(fā)的內(nèi)容指定到每一個(gè)具體的插槽上呢.
這個(gè)時(shí)候我們就需要給每個(gè)插槽指定名字
1.2 使用具名插槽和默認(rèn)插槽
<slot>
元素可以用一個(gè)特殊的特性 name
來進(jìn)一步配置如何分發(fā)內(nèi)容。多個(gè)插槽可以有不同的名字紧卒。具名插槽將匹配內(nèi)容片段中有對應(yīng) slot
特性的元素屡萤。
未使用name
屬性的slot
插槽被稱匿名插槽
, 也可以叫做默認(rèn)插槽
. 我們在子組件中仍然可以有一個(gè)匿名插槽箩兽,作為找不到匹配的內(nè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)對象
let MyChild = {
template: `#mychild`
};
// 實(shí)例中注冊組件
const vm = new Vue({
el:"#app",
components: {
MyChild
}
})
</script>
結(jié)果:
此時(shí)我們就會發(fā)現(xiàn),分發(fā)的內(nèi)容以及正常插入到對應(yīng)的插槽上了
通過上面的例子我們就知道了,slot
如果沒有顯示的使用name
屬性指定插槽的名字,那么slot默認(rèn)有個(gè)名字default
,默認(rèn)插槽,如果在分發(fā)內(nèi)容時(shí),沒有指定插槽,所有的內(nèi)容都將默認(rèn)插到默認(rèn)插槽上
2. 作用域插槽
2.1 作用插槽的理解和使用
通過學(xué)習(xí)我們知道,插槽的內(nèi)容最后是在子組件模板上渲染的, 那么就會在有得時(shí)候需要在分發(fā)的內(nèi)容中使用子組件中才有的數(shù)據(jù),怎么辦呢. 這個(gè)時(shí)候就要用到作用域插槽了
作用域插槽是一種特殊類型的插槽,用作一個(gè) (能被傳遞數(shù)據(jù)的) 可重用模板蒲祈,來代替已經(jīng)渲染好的元素甘萧。
簡而言之,就是利用slot
標(biāo)簽將子組件的數(shù)據(jù)傳遞到分發(fā)內(nèi)中上,就像prop
傳遞數(shù)據(jù)給組件一樣
在父級中,具有特殊特性 slot-scope
的 <template>
元素必須存在梆掸,表示它是作用域插槽的模板扬卷。slot-scope
的值將被用作一個(gè)臨時(shí)變量名,此變量接收從子組件傳遞過來的 props
對象:
示例:
<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)對象
let MyChild = {
template: `#mychild`,
data(){
return {
text: "提交"
}
}
};
// 實(shí)例中注冊組件
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>
很遺憾的告訴你, 具名插槽和作用域插槽的用法在未來即將被廢棄?
What? 那么我們怎么處理具名插槽和作用域插槽取消后留下的問題呢? 不用擔(dān)心,往下看.
3. v-slot指令
v-slot
指令自 Vue 2.6.0 起被引入,提供更好的支持slot
和slot-scope
attribute 的 API 替代方案卑硫。v-slot
完整的由來參見這份 RFC徒恋。在接下來所有的 2.x 版本中slot
和slot-scope
attribute 仍會被支持,但已經(jīng)被官方廢棄且不會出現(xiàn)在 Vue 3 中欢伏。
3.1 使用v-slot處理具名插槽的問題
在向具名插槽提供內(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)對象
let MyChild = {
template: `#mychild`
};
// 實(shí)例中注冊組件
const vm = new Vue({
el:"#app",
components: {
MyChild
}
})
</script>
顯示結(jié)果:
現(xiàn)在 <template>
元素中的所有內(nèi)容都將會被傳入相應(yīng)的插槽硝拧。任何沒有被包裹在帶有 v-slot
的 <template>
中的內(nèi)容都會被視為默認(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處理作用域插槽的問題
綁定在 <slot>
元素上的 attribute 被稱為插槽 prop≌咸眨現(xiàn)在在父級作用域中滋恬,我們可以使用帶值的 v-slot
來定義我們提供的插槽 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)對象
let MyChild = {
template: `#mychild`,
data(){
return {
text: "提交"
}
}
};
// 實(shí)例中注冊組件
const vm = new Vue({
el:"#app",
components: {
MyChild
}
})
</script>
顯示結(jié)果
3.3 作用域插槽的特殊處理
在上述情況下,當(dāng)被提供的內(nèi)容只有默認(rèn)插槽時(shí)咸这,組件的標(biāo)簽才可以被當(dāng)作插槽的模板來使用夷恍。這樣我們就可以把 v-slot
直接用在組件上:
<div id="app">
<!-- 使用組件 -->
<my-child v-slot:default="props">
<button>{{ props.text }}</button>
</my-child>
</div>
這種寫法還可以更簡單。就像假定未指明的內(nèi)容對應(yīng)默認(rèn)插槽一樣,不帶參數(shù)的 v-slot
被假定對應(yīng)默認(rèn)插槽:
<div id="app">
<!-- 使用組件 -->
<my-child v-slot="props">
<button>{{ props.text }}</button>
</my-child>
</div>
這用這種簡單語法的情況就是在組件中只有一個(gè)默認(rèn)插槽,一但有多個(gè)插槽,請使用完整的語法
4. 動態(tài)插槽
2.6.0 新增
動態(tài)指令參數(shù)也可以用在 v-slot
上酿雪,來定義動態(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)對象
let MyChild = {
template: `#mychild`
};
// 實(shí)例中注冊組件
const vm = new Vue({
el:"#app",
data:{
head:"title",
food:"time"
},
components: {
MyChild
}
})
</script>
此時(shí)template 標(biāo)簽上的v-solt指令參數(shù)是一個(gè)中括號, 中括號里的值將是一個(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í)候才可用醋安。這意味著以下語法是無效的:
<my-child >
<!-- 這種寫法無效 -->
<template #="props">
<h2>這是一篇介紹vue插槽的文章</h2>
</template>
</my-child>
如果你希望使用縮寫的話杂彭,你必須始終以明確插槽名取而代之:
<my-child >
<!-- 這種寫法有效,因?yàn)橛兄噶顓?shù) -->
<template #deatule="props">
<h2>這是一篇介紹vue插槽的文章</h2>
</template>
</my-child>