前言
插槽是Vue框架中的一個重要的概念,插槽的存在使得我們的組件更加具有靈活性,同時在多個開源的組件庫中,我們也常??梢钥吹接行╅_源組件也同樣預(yù)留了插槽讓我們?nèi)ミM行自定義的開發(fā),可以說插槽算是Vue開發(fā)所必須掌握的知識點了。本篇文章將對Slot插槽的使用進行講解,同時對具名插槽和作用域插槽的使用場景進行介紹,希望對大家有所幫助。
一、為什么要使用Slot
相信有過項目開發(fā)經(jīng)驗的小伙伴一定知道,在項目中往往會有多個地方需要用到樣式相似,細節(jié)略有差異的組件,比如說導(dǎo)航欄和搜索欄,這些組件出現(xiàn)頻率比較高,但是在不同的場景下我們對于導(dǎo)航欄的內(nèi)容有著不同的需要。而如果為了這點細微的區(qū)別再專門寫一個組件會十分麻煩,而且復(fù)用性也很低。
可能有些讀者會覺得,這不難解決,對于子組件中不確定的地方我們可以交由父組件的props傳值來進行解決,比如導(dǎo)航欄中的標題,我們可以都交由父組件傳值來實現(xiàn)。(比如下面的導(dǎo)航欄1和導(dǎo)航欄2)
不錯,當(dāng)組件的變化程度不大時,這確實可以十分方便地解決組件復(fù)用的問題。但如果說我想要實現(xiàn)根據(jù)不同的場景,導(dǎo)航欄中部的位置可能是標題,也有可能是下拉框,是搜索框或者是其他自定義的組件呢?此時我們就很難單純通過props來拓展我們的組件靈活性了。(比如下面的導(dǎo)航欄1和導(dǎo)航欄3)



二、slot插槽的基本使用
在子組件中,使用特殊的元素<slot>就可以為子組件開啟一個插槽。該插槽插入什么內(nèi)容取決于父組件如何使用。我們可以看一下下面這個案例:
我們一共在Vue實例中使用了2次子組件,第一次父組件沒有往子組件中傳遞元素,第二次父組件有往子組件傳遞元素。
<body>
<div id="app">
<slot-component></slot-component>
<slot-component>
<div>
<h4>父組件通過插槽改變默認子組件的默認內(nèi)容1</h4>
<h4>父組件通過插槽改變默認子組件的默認內(nèi)容2</h4>
</div>
</slot-component>
</div>
<template id="myComponent">
<div>
<slot>我是插槽的默認內(nèi)容</slot>
</div>
</template>
<script>
Vue.component('slot-component',{
template: '#myComponent'
})
let app = new Vue({
el: '#app',
})
</script>
</body>

從結(jié)果上看,當(dāng)父組件沒有往子組件插槽中添加元素時,則會展示插槽中默認的內(nèi)容,而如果父組件有傳遞插槽內(nèi)容,則會覆蓋插槽的默認內(nèi)容,而后進行顯示。
三、具名插槽
在第二小節(jié)中,我們已經(jīng)知道了插槽的基本使用,但是當(dāng)子組件的功能比較復(fù)雜時,我們可能就要在組件中定義多個插槽,來滿足更加靈活的業(yè)務(wù)需要。比如上面舉例的京東導(dǎo)航欄,這個組件內(nèi)部可以拆分為三個插槽,分別對應(yīng)左、右、中三個位置的內(nèi)容。
但想要在組件內(nèi)預(yù)留多個插槽有個前提條件,就是我們必須要讓每個插槽都有其對應(yīng)的唯一標識,這樣父組件傳遞內(nèi)容的時候,才能識別出來哪些內(nèi)容對應(yīng)哪個插槽。
我們可以看一下下面這個案例:
子組件內(nèi)定義了三個具名插槽,我們在父組件中進行子組件的調(diào)用,需要注意的是我們并沒有完全按照順序去傳遞對應(yīng)插槽的內(nèi)容。但實際上從演示結(jié)果中我們可以發(fā)現(xiàn),無論父組件傳遞的插槽內(nèi)容順序如何,最終解析的時候都會將傳入的插槽內(nèi)容根據(jù)slot name進行正確的渲染的。
<body>
<div id="app">
<slot-component></slot-component>
<br/><br/><br/>
<slot-component>
<div class="common-slot slot2" slot="slot2">
插槽2內(nèi)容
</div>
<div class="common-slot slot1" slot="slot1">
插槽1內(nèi)容
</div>
<div class="common-slot slot3" slot="slot3">
插槽3內(nèi)容
</div>
</slot-component>
</div>
<template id="myComponent">
<div>
<slot name="slot1">我是插槽1的默認內(nèi)容</slot>
<slot name="slot2">我是插槽2的默認內(nèi)容</slot>
<slot name="slot3">我是插槽3的默認內(nèi)容</slot>
</div>
</template>
<script>
Vue.component('slot-component',{
template: '#myComponent'
})
let app = new Vue({
el: '#app',
})
</script>
</body>

四、作用域插槽
(一)編譯作用域
在講解作用域插槽之前,我們需要先對編譯作用域進行理解。具體表現(xiàn)在父組件模板的所有東西都會在父級作用域內(nèi)編譯;子組件模板的所有東西都會在子級作用域內(nèi)編譯。
我們可以通過下面這個案例來理解這個規(guī)則:
父組件和子組件都使用了isShow來控制組件的顯示,同時在父子組件的data中,又都有同名的變量isShow。我們從結(jié)果中可以看到,定義在在父組件中子組件,其組件是否可見取決于父組件data中的變量值。而在子組件template中定義的isShow標識,則受子組件自身data變量的約束,也就是說此處子組件模板的變量取的是子級作用域中的變量值。
<body>
<div id="app">
<slot-component v-show="isShow"></slot-component>
</div>
<template id="myComponent">
<div>
<h2>HELLO</h2>
<div v-show="isShow">
HI
</div>
</div>
</template>
<script>
Vue.component('slot-component', {
template: '#myComponent',
data() {
return {
isShow: false
}
}
})
let app = new Vue({
el: '#app',
data: {
isShow: true
}
})
</script>
</body>

(二)作用域插槽
在上一小節(jié)的演示中,我們已經(jīng)可以了解到編譯作用域的概念,也知道了父組件無法直接使用子組件內(nèi)部的數(shù)據(jù)(因為子組件模板內(nèi)部的數(shù)據(jù)是在子組件的作用域中的)。但有些場景下,我們又會需要父組件可以替換插槽的標簽,但是內(nèi)容由子組件來提供。那么,此時我們就可以使用作用域插槽來解決這個問題。
我們可以來看一下下面這個案例:子組件中存在一個數(shù)組,現(xiàn)在我們想要通過插槽的方式,來根據(jù)不同的需要實現(xiàn)數(shù)組的展示方式:
在父組件中,我們定義了2種展示數(shù)據(jù)的方式,一種為展示為列表形式,還有一種是每種語言以--進行分割。在使用上,子組件需要在插槽處通過:data的方式提供對外暴露的數(shù)據(jù),父組件在使用的時候,則是先在子組件內(nèi)部定義<template>標簽,從slot-scope屬性中取出slotProps參數(shù)(其實slotProps就是一個對象,里面封裝著所有子組件插槽對外暴露的數(shù)據(jù))。
我們通過slotProps.data就可以獲取到我們在子組件插槽中封裝的data數(shù)據(jù)啦
<body>
<div id="app">
<slot-component>
<template slot-scope="slotProps">
<ul>
<li v-for="lang in slotProps.data">{{lang}}</li>
</ul>
</template>
</slot-component>
<slot-component>
<template slot-scope="slotProps">
<ul>
<span v-for="(lang,index) in slotProps.data">
<span v-if="index<5">{{lang}}--</span>
<span v-else>{{lang}}</span>
</span>
</ul>
</template>
</slot-component>
</div>
<template id="myComponent">
<div>
<slot :data="languages"></slot>
</div>
</template>
<script>
Vue.component('slot-component', {
template: '#myComponent',
data() {
return {
languages: [
'python', 'java', 'go', 'c#', 'scala', 'javaScript'
]
}
}
})
let app = new Vue({
el: '#app',
})
</script>
</body>

至此,有關(guān)插槽的內(nèi)容就到此結(jié)束啦,作用域插槽多見于常見的組件庫中(比較多是在table組件中出現(xiàn)),所以最好要熟悉插槽的原理和使用,這樣可以更好地簡化我們的開發(fā)工作