Vue 插槽(slot)詳細介紹(對比版本變化,避免踩坑)
Vue 插槽(slot)詳細介紹(對比版本變化,避免踩坑):https://blog.csdn.net/qq_41809113/article/details/121640035
Vue中的插槽(slot)在專案中用的也是比較多的,今天就來介紹一下插槽的基本使用以及Vue版本更新之後的插槽用法變化。
插槽是什麼?
插槽就是子元件中的提供給父元件使用的一個佔位符,用<slot></slot> 表示,父元件可以在這個佔位符中填充任何模板程式碼,如 HTML、元件等,填充的內容會替換子元件的<slot></slot>標籤。簡單理解就是子元件中留下個“坑”,父元件可以使用指定內容來補“坑”。以下舉例子幫助理解。
怎麼使用插槽?
基本用法
現在,有兩個元件,A與B,分別如下:
A.vue
<template>
<div>
<p>我是A元件</p>
</div>
</template>
<script>
export default {
name:'A',
data(){
return {
}
}
}
</script>
B.vue
<template>
<div>
<p>我是B元件</p>
</div>
</template>
<script>
export default {
name:'B',
data(){
return {
}
}
}
</script>
將B元件引入A元件裡面(此時B為A的子元件)
<template>
<div>
<p>我是A元件</p>
<B><B/>
</div>
</template>
<script>
import B from './B.vue' //引入B元件
export default {
name:'A',
components:{ //註冊B元件
B
},
data(){
return {
}
}
}
</script>
頁面效果如下:
準備工作完畢,現在,在B元件裡面使用插槽(slot)
<template>
<div>
<p>我是B元件</p>
<slot></slot> //插槽的使用方式
</div>
</template>
<script>
export default {
name:'B',
data(){
return {
}
}
}
</script>
此時頁面並無變化(最開始的情況),當然,B元件中使用了插槽slot之後,相當於留下了一個“坑”,佔了個位置。 那麼如何驗證其存在了呢?
此時,修改A元件裡面的程式碼
<template>
<div>
<p>我是A元件</p>
<B>
驗證插槽是否生效 //用B元件標籤包裹內容,驗證slot
</B>
</div>
</template>
<script>
import B from './B.vue'
export default {
name:'A',
components:{
B
},
data(){
return {
}
}
}
</script>
此時頁面的效果如下:
頁面中多出了在A中用B包裹的內容。沒錯,這就是插槽的基本使用,是不是很簡單?
Vue 實現了一套內容分發的 API,這套 API 的設計靈感源自 Web Components 規範草案,將 <slot> 元素作為承載分發內容的出口。
如上面的例子,當元件渲染的時候,<slot></slot> 將會被替換為“驗證插槽是否生效”(即指定內容)。插槽內可以包含任何模板程式碼,包括 HTML:
<template>
<div class="main">
<p>我是A元件</p>
<B>
<span style="color:red">驗證插槽是否生效</span> //內容為html
</B>
</div>
</template>
頁面效果如下:
插槽內也可以放其他元件,如此時再新建一個元件C:
<template>
<div>
<p>我是C元件</p>
</div>
</template>
<script>
export default {
name:'C',
data(){
return {
}
}
}
</script>
在A元件中,將B元件包裹的內容換成C元件:
<template>
<div class="main">
<p>我是A元件</p>
<B>
<!-- <span style="color:red">驗證插槽是否生效</span> -->
<C /> //插入C元件
</B>
</div>
</template>
<script>
import B from './B.vue'
import C from './C.vue' //引入C元件
export default {
name:'A',
components:{
B,
C //註冊C元件
},
data(){
return {
}
}
}
</script>
頁面效果如下:
此時檢查頁面元素,我們會發現,在原本B元件中<slot></slot>的位置,替換成了C元件:
//B.vue
<template>
<div>
<p>我是B元件</p>
<slot></slot>
</div>
</template>
//觀察頁面元素,<slot></slot>被替換成C元件
也印證了開篇對插槽作用的解釋,即使用<slot></slot>的元件指定的位置留一個坑,如果在外部,使用其元件包裹某內容(可以是任何模板程式碼,也可以是HTML,還可以是元件),則該內容就會被分發到<slot></slot>處(一個有趣的說法就是把“坑”補上),渲染出來。當然,也可以不放任何內容,不影響元件渲染,就好比最開始的情況。
注意:如果B元件的 template 中沒有包含一個 <slot> 元素,即不使用插槽,則該元件起始標籤和結束標籤之間的任何內容都會被拋棄。例如:
//B.vue
<template>
<div>
<p>我是B元件</p>
<!-- <slot></slot> --> //不使用插槽
</div>
</template>
//A.vue
<template>
<div>
<p>我是A元件</p>
<B>
<!-- <span style="color:red">驗證插槽是否生效</span> -->
<C />
</B>
</div>
</template>
//此時在<B></B>包裹的內容都會被拋棄
頁面效果如下,在B元件中插入的C元件被拋棄了,因為B元件中沒使用插槽:
後備(預設)內容
有時為一個插槽設定具體的後備 (也就是預設的) 內容是很有用的,它只會在沒有提供內容的時候被渲染。例如在B元件中:
<template>
<div>
<slot></slot>
</div>
</template>
我們可能希望這個B元件內絕大多數情況下都渲染文字“我是B元件”。為了將“我是B元件”作為後備內容,我們可以將它放在 <slot> 標籤內:
<template>
<div>
<slot><p>我是B元件</p></slot>
</div>
</template>
現在當我在一個父級元件中使用B元件並且不提供任何插槽內容時:
<B></B>
後備內容“我是B元件”將會被渲染:
但是如果我們提供內容:
<B>
<p>我是插槽內容</p>
</B>
則這個提供的內容將會被渲染從而取代後備內容:
具名插槽
所謂具名插槽,顧名思義就是起了名字的插槽。有時我們需要多個插槽,例如當我們想使用某種通用模板:
<template>
<div>
<header>
<!-- 我們希望把頁頭放這裡 -->
</header>
<main>
<!-- 我們希望把主要內容放這裡 -->
</main>
<footer>
<!-- 我們希望把頁尾放這裡 -->
</footer>
</div>
</template>
對於這樣的情況,<slot> 元素有一個特殊的 attribute:name。這個 attribute 可以用來定義額外的插槽:
//B.vue
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
一個不帶 name 的 <slot> 出口會帶有隱含的名字“default”。
在向具名插槽提供內容的時候,我們可以在一個 <template> 元素上使用 slot 指令,並以 slot 的引數的形式提供其名稱(當然也可以直接放在標籤中,如<div slot="header">):
<template>
<div>
<p>我是A元件</p>
<B>
<template slot="header">
<p>我是header部分</p>
</template>
<p>我是main(預設插槽)部分</p>
<template slot="footer">
<p>我是footer部分</p>
</template>
</B>
</div>
</template>
現在 <template> 元素中的所有內容都將會被傳入相應的插槽。任何沒有被包裹在帶有slot 的 <template> 中的內容都會被視為預設插槽的內容。
頁面效果如下:
觀察頁面元素,內容被放入相應名字的插槽中:
Tips:說到這裡就不得不提一下,這種方式在專案中比較常用,可以當成一個複用(通用)模板元件。如多個元件的佈局使用相似模板,只是具體內容不同,那麼我們可以使用這種插槽方式封裝成一個通用元件,在其他元件使用的時候只需要傳對應的內容到對應名字的插槽即可,不需要將該模板在每個元件重新寫一遍,減少程式碼冗餘,大大提高開發效率。
作用域插槽
有時讓插槽內容能夠訪問子元件中才有的資料是很有用的。現在,假設B元件:
<template>
<div>
<p>我是B元件</p>
<slot>{{obj.firstName}}</slot>
</div>
</template>
<script>
export default {
name:'B',
data(){
return {
obj:{
firstName:'leo',
lastName:'lion'
}
}
}
}
</script>
我們可能想換掉備用內容,用“lion”來顯示。如下,在A元件:
<template>
<div>
<p>我是A元件</p>
<B>
{{obj.lastName}}
</B>
</div>
</template>
然而上述程式碼不會正常工作,因為只有B元件可以訪問到 obj,而我們提供的內容是在父級渲染的,即在父級作用域中。頁面並無變化:
為了讓 obj在父級的插槽內容中可用,我們可以將 obj作為 <slot> 元素的一個 attribute 繫結上去:
<template>
<div>
<p>我是B元件</p>
<slot :obj="obj">{{obj.firstName}}</slot>
</div>
</template>
繫結在 <slot> 元素上的 attribute 被稱為插槽 prop。現在在父級作用域中,我們可以使用帶值的 slot-scope 來定義我們提供的插槽 prop 的名字:
<template>
<div class="main">
<p>我是A元件</p>
<B>
<template slot-scope="data">
{{data.obj.lastName}}
</template>
</B>
</div>
</template>
在這個例子中,我們選擇將包含所有插槽 prop 的物件命名為 data,但你也可以使用任意你喜歡的名字。此時頁面效果如下:
如果你有使用過ElementUI裡面的表格el-table,當改變某一列展示的欄位時,我們經常使用:
<el-table-column>
<template slot-scope="scope">
<span>{{scope.row.xxx}}</span>
</template>
</el-table-column>
插槽版本變化
v-slot 指令自 Vue 2.6.0 起被引入,提供更好的支援 slot 和 slot-scope attribute 的 API 替代方案。v-slot 完整的由來參見這份 RFC。在接下來所有的 2.x 版本中 slot 和 slot-scope attribute 仍會被支援,但已經被官方廢棄且不會出現在 Vue 3 中。也就是說,在vue2版本中,我們仍可以使用slot跟slot-scope,但是在vue3中就只能使用v-slot了。
原來的帶有slot的具名插槽
//B.vue
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
寫法變化,使用v-slot
<template>
<div>
<p>我是A元件</p>
<B>
<template v-slot:header>
<p>我是header部分</p>
</template>
<p>我是main(預設插槽)部分</p>
<template v-slot:footer>
<p>我是footer部分</p>
</template>
</B>
</div>
</template>
原來的作用域插槽
<template>
<div class="main">
<p>我是A元件</p>
<B>
<template slot-scope="data">
{{data.obj.lastName}}
</template>
</B>
</div>
</template>
寫法變化,使用v-slot
<template>
<div class="main">
<p>我是A元件</p>
<B>
<template v-slot="data">
{{data.obj.lastName}}
</template>
</B>
</div>
</template>
在 2.6.0 中,為具名插槽和作用域插槽引入了一個新的統一的語法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 這兩個目前已被廢棄但未被移除且仍在文件中的 attribute。新語法的由來可查閱這份 RFC。注意slot版本變化,vue2中仍可以使用slot與slot-scope,但是vue3只能使用v-slot了,切記,避免踩坑。
————————————————
版權宣告:本文為CSDN博主「前端不釋卷leo」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/qq_41809113/article/details/121640035