前言
Vue中的插槽是一個(gè)非常強(qiáng)大的功能,在復(fù)用組件模塊的時(shí)候,針對(duì)相似的結(jié)構(gòu),擁有不通的內(nèi)容時(shí),使用插槽就非常方便,一定程度上可以減少在模板中使用大量的邏輯判斷,控制顯示不通的內(nèi)容
同時(shí),也可以讓代碼組織結(jié)構(gòu)更加清晰,雖然使用上是簡(jiǎn)單了,但是插槽有些不是很好理解俐筋,不是很直觀
它是讓父組件可以向子組件指定位置處插入一html結(jié)構(gòu),自由靈活,也是組件間的一種通信方式
形式上有,默認(rèn)插槽,具名插槽還有作用域插槽
大家在使用element-ui
表格的時(shí)候,雖然都知道怎么用,表頭,以及內(nèi)容模板的渲染,就使用了插槽,但是往往是很迷糊的
因?yàn)楸怀橄罅说?/p>
今天就一起來(lái)學(xué)習(xí)下,學(xué)完之后,在看element-ui
表格的時(shí)候,希望能給你帶來(lái)一些啟發(fā),下次再次使用時(shí),理解更上一層樓
默認(rèn)插槽
官方文檔里介紹到:Vue
實(shí)現(xiàn)了一套內(nèi)容分發(fā)的 API
厂镇,這套 API
的設(shè)計(jì)靈感源自 Web Components
規(guī)范草案,將 <slot>
元素作為承載分發(fā)內(nèi)容的出口
這句話不是很好理解,換句話說(shuō),也就是,<slot>
可以充當(dāng)元素標(biāo)簽的占位符,可以代替在父組件引用的組件內(nèi)的html
標(biāo)簽內(nèi)容
以如下示例所示
在App組件中引入SlotBase.vue
組件
<template>
<div id="app">
<SlotBase
:lists="lists">
<p>默認(rèn)內(nèi)容</p>
</SlotBase>
</div>
</template>
<script>
import SlotBase from "./components/SlotBase.vue"
export default {
name: 'App',
components: {
SlotBase
},
data() {
return {
lists: [
{
id: "001",
title: "直播賣酒"
},
{
id: "002",
title: "直播打賞"
},
{
id: "003",
title: "直播炫富"
}
]
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
而在編寫(xiě)SlotBase.vue
組件中,引入slot
標(biāo)簽,如下所示
<template>
<div class="wrap">
<div class="list" v-for="list in lists" :key="list.id">
{{list.title}}
<!-- 此處引入slot標(biāo)簽 -->
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "SlotBase",
props: {
lists: {
type: Array
}
},
mounted() {
console.log(this.lists);
}
}
</script>
<style lang="scss" scoped>
.wrap {
display: flex;
justify-content: center;
}
.list {
width: 400px;
height: 200px;
border:1px solid red;
margin-right: 10px;
}
</style>
在子組件內(nèi)的<slot></slot>
標(biāo)簽就是插槽,代替了在父組件內(nèi)的<p>默認(rèn)內(nèi)容</p>
如果你在父組件的自定義標(biāo)簽內(nèi),插入了html
模板,在子組件沒(méi)有使用slot
,那么父組件內(nèi)插入的標(biāo)簽內(nèi)容是不會(huì)被插入進(jìn)去的
現(xiàn)在知道插槽是什么了吧,可以在組件標(biāo)簽內(nèi)定義需要的內(nèi)容冲簿,通過(guò)插槽加入到組件內(nèi)部中
組件內(nèi)部的<slot></slot>
元素就好像一個(gè)傳送門(mén)锣夹,也就是所謂的槽浪南,它提供了內(nèi)容的入口父款,也決定了內(nèi)容的位置浅役。 組件標(biāo)簽中定義的內(nèi)容斩松,通過(guò)這個(gè)“傳送門(mén)”就可以加入到組件內(nèi)部中
插槽中的“插件”就是組件標(biāo)簽中的內(nèi)容。
插槽中的“槽”就是在組件中的<slot></slot>
元素,當(dāng)沒(méi)有<slot></slot>
元素的時(shí)候觉既,就不渲染組件標(biāo)簽中的內(nèi)容
當(dāng)是默認(rèn)插槽時(shí),我們可以使用template
標(biāo)簽給包裹起來(lái)的,并且在上面添加v-slot:default
屬性,這代表的是默認(rèn)插槽
<template v-slot:default>
<p>默認(rèn)內(nèi)容</p>
</template>
具名插槽
如果要將不通的內(nèi)容放在不通的位置,那么默認(rèn)插槽就無(wú)法辦到了
顧名思義,具名插槽,就是給插槽定義一個(gè)名字,讓每個(gè)不通的模板對(duì)應(yīng)著不通的名字
我們給在父組件內(nèi)的插入的模板屬性上添加v-slot:插槽名字
,而在子組件內(nèi)通過(guò)添加name屬性<slot name="插槽名字"></slot>
需要注意的是,name
的值需要與v-slot
的值要一一對(duì)應(yīng),如果對(duì)不上的話,那么就會(huì)達(dá)不到我們預(yù)期的效果
如下示例代碼所示:在App父組件中
<template>
<div id="app">
<SlotBase
:lists="lists">
<template v-slot:default>
<p>默認(rèn)內(nèi)容</p>
</template>
<template v-slot:content>
<p>我是直播賣酒-content</p>
</template>
<!-- <template v-slot:content2>
<p>我是直播打賞-content</p>
</template> -->
<!-- 可以簡(jiǎn)寫(xiě)成如下所示 -->
<template #content2>
<p>我是直播打賞-content</p>
</template>
</SlotBase>
</div>
</template>
<script>
import SlotBase from "./components/SlotBase.vue"
export default {
name: 'App',
components: {
SlotBase
},
data() {
return {
lists: [
{
id: "001",
title: "直播賣酒",
},
{
id: "002",
title: "直播打賞"
},
{
id: "003",
title: "直播炫富"
}
]
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
而在子組件,slotBase.vue
中
<template>
<div class="wrap">
<div class="list" v-for="list in lists" :key="list.id">
{{list.title}}
<!-- 此處引入slot標(biāo)簽 -->
<slot></slot>
<slot name="content" v-if="list.title =='直播賣酒'"></slot>
<slot name="content2" v-if="list.title =='直播打賞'"></slot>
</div>
</div>
</template>
<script>
export default {
name: "SlotBase",
props: {
lists: {
type: Array
}
},
mounted() {
console.log(this.lists);
}
}
</script>
<style lang="scss" scoped>
.wrap {
display: flex;
justify-content: center;
}
.list {
width: 400px;
height: 200px;
border:1px solid red;
margin-right: 10px;
}
</style>
上面我用了一個(gè)v-if
條件渲染表達(dá)式,我們可以可以根據(jù)一些條件控制元素的顯示和隱藏
上面的具名插槽,在父組件中v-slot:content
可以縮寫(xiě)為#content
,當(dāng)我們看到這種簡(jiǎn)寫(xiě)的時(shí)候,知道它也是給插槽起一個(gè)具體的名字即可
它跟 v-on
和 v-bind
一樣惧盹,v-slot
也有縮寫(xiě)乳幸,即把參數(shù)之前的所有內(nèi)容 (v-slot:
) 替換為字符 #
。例如 v-slot:header
可以被重寫(xiě)為 #header
如果你看不懂,那就是對(duì)簡(jiǎn)寫(xiě)插槽的名稱有些陌生了
從上面的示例中,我們可以做出一些總結(jié)
- 具名插槽可以根據(jù)名稱渲染對(duì)應(yīng)的html標(biāo)簽?zāi)0鍍?nèi)容
- 沒(méi)有定義名稱的內(nèi)容會(huì)被默認(rèn)插槽統(tǒng)一渲染
- 默認(rèn)插槽其實(shí)也是一個(gè)具名插槽,名稱為
default
- 父組件內(nèi)插槽內(nèi)容可以是模板
html
標(biāo)簽元素,也可以是組件
注意
這個(gè)v-slot
只能用在template
標(biāo)簽上
舊版本寫(xiě)法
在父組件上使用v-slot:插槽名稱
,這個(gè)是vue2.6.0
以后的寫(xiě)法,在vue2.6.0
之前,可以在模板上使用slot="插槽的名稱"
作用域插槽
相比于默認(rèn)插槽,具名插槽,作用域插槽有些難以理解
如果你理解js中的作用域鏈和Es6中的塊級(jí)作用域,那么對(duì)于銜接作用域插槽,可能會(huì)好些
有時(shí)钧椰,讓插槽內(nèi)容能夠訪問(wèn)子組件中才有的數(shù)據(jù),是很有用的
插槽中內(nèi)容的流動(dòng)方向是從組件標(biāo)簽傳到組件內(nèi)部
而作用域插槽則讓作用域反向流動(dòng),從組件內(nèi)部傳到組件標(biāo)簽內(nèi),可以在組件標(biāo)簽內(nèi)訪問(wèn)到組件內(nèi)部的變量粹断,
換而言之,在父組件的模板中,如何拿到子組件傳遞過(guò)來(lái)的數(shù)據(jù),而子組件(插槽)內(nèi)部定義的數(shù)據(jù),如何傳遞到父組件當(dāng)中去
也就是可以通過(guò)作用域插槽傳遞數(shù)據(jù)
我們?cè)?code>slotBase.vue組件中內(nèi)部定義一個(gè)數(shù)據(jù)msg
<template>
<div class="wrap">
<div class="list" v-for="list in lists" :key="list.id">
{{list.title}}
<!-- 此處引入slot標(biāo)簽 -->
<slot></slot>
<!-- v-bind,自定義屬性的方式向slot插槽傳遞了屬性-->
<slot name="content"
v-if="list.title =='直播賣酒'"
:msg="msg"></slot>
<slot name="content2" v-if="list.title =='直播打賞'"></slot>
</div>
</div>
</template>
<script>
export default {
name: "SlotBase",
props: {
lists: {
type: Array
}
},
data() {
return {
// 子組件定義的數(shù)據(jù)
msg: "itclanCoder"
}
},
mounted() {
console.log(this.lists);
}
}
</script>
<style lang="scss" scoped>
.wrap {
display: flex;
justify-content: center;
}
.list {
width: 400px;
height: 200px;
border:1px solid red;
margin-right: 10px;
}
</style>
在上面的代碼中,在slot
元素上綁定了msg
屬性,這個(gè)attribute
被稱為插槽prop
那么在父級(jí)作用域中,又該如何接收子組件傳遞過(guò)來(lái)的數(shù)據(jù)呢
在v2.6.0
中使用的是v-slot:插槽名="slotProps"
,其中這個(gè)slotProps
是自己任意定義的,名字自己隨意
代碼如下所示:
<template v-slot:content="slotProps">
{{slotProps.msg}}
</template>
// 也可以縮寫(xiě)為#插槽名="屬性Props"
<template #content="slotProps">
{{slotProps.msg}}
</template>
而在舊版本中,也可以這么寫(xiě)
<template slot="content" slot-scope="slotProps">
{{slotProps.msg}}
</template>
新版本的寫(xiě)法與vue2.6.0以下的版本不能混寫(xiě),注意,這種廢棄的語(yǔ)法,在vue3.0
中不會(huì)出現(xiàn)了的
所以還是用最新的寫(xiě)法吧,但是一些老的vue2.0項(xiàng)目,舊版本的寫(xiě)法,要看的懂的
以上就是默認(rèn)插槽,具名插槽,作用域插槽的使用,插槽是一個(gè)非常強(qiáng)大的功能,在組件的復(fù)用時(shí),對(duì)于復(fù)用結(jié)構(gòu)和精簡(jiǎn)代碼非常有用
如果大家有做過(guò)那種后臺(tái)cms管理系統(tǒng),針對(duì)很多不同種類的各種表單彈窗,而表單彈窗內(nèi),有時(shí)要根據(jù)后端返回的接口props
去顯示指定的內(nèi)容
這時(shí)候,插槽就非常有用了
獨(dú)占默認(rèn)插槽的縮寫(xiě)
當(dāng)被提供的內(nèi)容只有默認(rèn)插槽時(shí),組件的標(biāo)簽才可以被當(dāng)做插槽的模板來(lái)使用
我們可以直接把v-slot
直接用在組件上
<CurrentUser v-slot:default="slotProps">
<p>{{slotProps.user}}</p>
</CurrentUser>
還可以在簡(jiǎn)化一下嫡霞。就像假定未指明的內(nèi)容對(duì)應(yīng)默認(rèn)插槽一樣瓶埋,不帶參數(shù)的 v-slot
被假定對(duì)應(yīng)默認(rèn)插槽
<CurrentUser v-slot="slotProps">
<p>{{slotProps.user}}</p>
</CurrentUser>
需要注意的是,以下寫(xiě)法是不可以的,當(dāng)v-slot
用在自定義標(biāo)簽組件上,不能縮寫(xiě)
Named slots must use '<template>' on a custom element
<CurrentUser #slotProps>
<p>{{slotProps.user}}</p>
</CurrentUser>
::: tip 注意
默認(rèn)插槽的縮寫(xiě)語(yǔ)法不能和具名插槽混用,因?yàn)樗鼤?huì)導(dǎo)致作用域不明確
<!-- 無(wú)效,會(huì)導(dǎo)致警告 -->
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
<template v-slot:other="otherSlotProps">
slotProps is NOT available here
</template>
</current-user>
:::
只要出現(xiàn)多個(gè)插槽,所有的插槽使用完整的基于template
的語(yǔ)法
也就是說(shuō),v-slot
用在template
標(biāo)簽上
<current-user>
<template v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</template>
<template v-slot:other="otherSlotProps">
...
</template>
</current-user>
總結(jié)
以上本節(jié)的內(nèi)容,插槽是一個(gè)非常強(qiáng)大的功能,默認(rèn)插槽在子組件內(nèi)部使用<slot></slot>
進(jìn)行占位,而在父組件內(nèi),使用html
標(biāo)簽,或者組件
如果子組件使用了多個(gè)插槽诊沪,那么就使用具名插槽對(duì)每個(gè)插槽進(jìn)行區(qū)分,子組件內(nèi)的<slot name="插槽名稱"></slot>
,而在父組件中,使用template
標(biāo)簽
<template v-slot:插槽名稱></template>
,其中v-slot
有簡(jiǎn)寫(xiě)#插槽名稱
,可以使用在具體的標(biāo)簽上,但是當(dāng)有多個(gè)插槽時(shí),只能用在template
標(biāo)簽上
當(dāng)父組件想要拿到子組件中的數(shù)據(jù),子組件內(nèi)部又是如何把內(nèi)部數(shù)據(jù)傳遞到外部組件中去的呢,在子組件內(nèi)部是通過(guò)在slot
插槽props
傳遞到父父組件當(dāng)中去的
而在父組件當(dāng)中,通過(guò)v-slot:插槽名="slotProps"
進(jìn)行接收,這個(gè)slotProps
是一個(gè)集合對(duì)象,接收了子組件props
的
這就是作用域插槽,它也是父子組件傳遞數(shù)據(jù)的一種方式