vue - 插槽詳解
目錄
什麼是插槽
官方文件是這樣說明插槽的:
Vue 實現了一套內容分發的 API, 這套 API 的設計靈感源自 Web 規範草案, 將 <slot> 元素作為承載分發內容的出口。
插槽,簡單說,插槽就是杯子,杯子裡面裝的是飲料還是牛奶,由外部倒入什麼來決定 ,就好比下面的程式碼,有一個子元件,他有部分內容,需要根據我當前頁面需要來展示,將html模板傳入到子元件就需要使用插槽。
如下所示,定義一個子元件item,用solt標籤定義一個預設插槽,為在父元件使用時,需要傳遞到item元件的模板,佔個位置。 這樣在父元件在item子元件中編寫的html模板就會被渲染到子元件。
預設插槽
// 父元件 <template> <tab> <item > <div>裝一杯牛奶</div> <item> <tab> </template> // item子元件 <template> <div> <slot></slot> //預設插槽 在父元件使用item子元件,item標籤包裹的內容將預設被渲染到子元件的solt中 <h1>我是杯子</h1> </div> </template>
這樣的好處,顯而易見,可以讓元件模組化更清晰,同時複用性更高。不至於我要一杯茶,我就要定義一個元件,我要一杯牛奶我又定義一個元件,有了插槽,我只需要定義一個杯子,要喝什麼由使用的傳入內容決定。
上述程式碼也叫預設插槽,就是預設把模板全部渲染到 solt 中,如果需要指定渲染,就需要使用具名插槽,簡單說就是起一個名字,告訴他小紅該坐那兒,小明該坐那兒
具名插槽
//父級 <template> <div> <layout> <template v-solt:header>頭部標題</template> <div>顯示的內容</div> <template v-solt:footer>尾部</template> </layout> </div> </template> //layout子元件 <template> <div> <layout> <h1>layout子元件</h1> <slot name="header"></slot> //這種就叫具名插槽 <slot></slot> //如果不指定名字,就會將模板中未匹配到的內容渲染到預設插槽中,這裡為顯示的內容 <slot name="footer"></slot> </layout> </div> </template>
一個不帶 name 的 <slot> 出口會帶有隱含的名字“default”。
在向具名插槽提供內容的時候, 我們應該在<template> 元素上使用 v-slot 指令, 並以 v-slot 的引數的形式提供其名稱: v-slot:heade
現在 <template> 元素中的所有內容都將會被傳入相應的插槽。 任何沒有被包裹在帶有 v-slot 的 <template> 中的內容都會被視為預設插槽的內容
作用域插槽
父元件提供了模板給子元件,那麼子元件如何反饋給父元件呢,例如:我定義了一個杯子,我需要告訴使用的人,我這個杯子,只能裝300mL,這時我們就需要用v-slot來接收子元件上通過v-bind繫結的值。
作用域插槽,就是能讓插槽內容訪問到子元件中才有的資料
//父級
<template>
<div>
<cup>
<template v-slot:size="data"> // 這裡將包含所有插槽 prop 的物件命名為 data, 也可以命名為其他的名字
{{ data.msg }}
</template>
// vue 2.6 之前的寫法, 用 slot 接收 name, slot-scope 接收子元件繫結的資料
//<div solt="size" slot-scope="data">
// {{data.msg}}
//</div>
</cup>
</div>
</template>
//cup子元件
<template>
<div>
<slot name="size" :msg="msg"></slot> // 繫結在 <slot> 元素上的特性被稱為插槽 prop。
</div>
</template>
<script>
export default {
data(){
return{
msg:'300mL大小的杯子'
}
}
}
</script>
解構prop的寫法,ES6 語法, 與上面的寫法等價
//父級
<template>
<div>
<cup>
<template v-slot:size="{ msg }">
{{ msg }}
</template>
// 解構 並重命名
//<template v-slot:size="{ msg : info }">
// {{ info }}
//</template>
</cup>
</div>
</template>
上面有說到 vue2.6之前插槽的版本,之後vue官方廢棄了上面的語法,改為v-solt來代替,區別在於
- vue 2.6 之後的版本 v-slot 指令合併了solt 和solt-scope 這兩個attribute,寫法更加簡潔
- 語義化更明顯
- 2.6之前的寫法會出現作用域混淆的問題
獨佔預設插槽
v-slot 只能新增在一個 <template> 上 (只有一種例外情況), 這一點和已經廢棄的 slot 特性不同。而這個例外就是 獨佔預設插槽。
當被提供的內容只有預設插槽時, 元件的標籤才可以被當作插槽的模板來使用。 這樣我們就可以把 v-slot 直接用在元件上:
父元件
<template>
<item v-slot:default="data"> //v-slot:default可以不加 v-slot="data"
{{ data.msg }}
<item>
</template>
//item子元件
<template>
<div>
<slot :msg="msg"></slot>//預設插槽
</div>
</template>
預設插槽的縮寫語法不能和具名插槽混用,因為它會導致作用域不明確。下面是官方的例子:
<!-- 無效,會導致警告 -->
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
<template v-slot:other="otherSlotProps">
slotProps is NOT available here
</template>
</current-user>
注意:只要出現多個插槽, 請始終為所有的插槽使用完整的基於 <template> 的語法
動態插槽名
v-slot 支援2.6的動態引數寫法
<layout>
<template v-slot:[attributeName]>
...
</template>
</layout>
這裡的 attributeName 會被作為一個 JavaScript 表示式進行動態求值,求得的值將會作為最終的引數來使用。例如,如果你的 Vue 例項有一個 data property attributeName,其值為 "header",那麼這個繫結將等價於 v-slot:header。
具名插槽的縮寫
v-slot 也有縮寫, 即把引數之前的所有內容( v-slot: ) 替換為字元 # 。 例如 v-slot:header 可以被重寫為 #header
//父級
<template>
<div>
<layout>
<template #header>頭部標題</template> // 具名插槽的縮寫
<div>顯示的內容</div>
<template v-solt:footer>尾部</template>
</layout>
</div>
</template>
//layout子元件
<template>
<div>
<layout>
<h1>layout子元件</h1>
<slot name="header"></slot> //這種就叫具名插槽
<slot></slot> //如果不指定名字,就會將模板中未匹配到的內容渲染到預設插槽中,這裡為顯示的內容
<slot name="footer"></slot>
</layout>
</div>
</template>
注意: 該縮寫只在其有引數(例如:name)的時候才可用。