前言
vue 插槽,目前到3.0有3種方式,第一種,在2.6之前使用的是slot 和 slot-scpe 2.6後已被官方廢棄,但在2.x版本仍被支持,第二種是vue 在2.6版本後更新的新指令 v-slot 來替代slot 和slot-scpe
那麼什麼是插槽呢,作用又是什麼
插槽,簡單說,插槽就是杯子,杯子裏面裝的是飲料還是牛奶,由外部倒入什麼來決定 ,就好比下面的代碼,我需要一個子組件,他有部分內容,需要根據我當前頁面需要來展示,我如何將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>
<div solt="header">頭部標題</div>
<div >顯示的內容</div>
<div slot="footer">尾部</div>
</layout>
</div>
</template>
//layout子組件
<template>
<div>
<layout>
<h1>layout子組件</h1>
<slot name="header"></slot> //這種就叫具名插槽
<slot></slot> //如果不指定名字,就會將模板中未匹配到的內容渲染到默認插槽中,這裏爲顯示的內容
<slot name="footer"></slot>
</layout>
</div>
</template>
**tip:**當你的子組件中 如layout 中並不存在,slot這個元素,那麼在父頁面中 這個標籤中的內容都會被拋棄
作用域插槽
父組件提供了模板給子組件,那麼子組件如何反饋給父組件呢,例如:我定義了一個杯子,我需要告訴使用的人,我這個杯子,只能裝300mL,這時我們就需要用slot-scope來接收子組件上通過v-bind綁定的值。
作用域插槽,就是能讓插槽內容訪問到子組件中才有的數據
//父級
<template>
<div>
<cup>
<div solt="size" slot-scope="data">
{{data.msg}}
</div>
</cup>
</div>
</template>
//cup子組件
<template>
<div>
<slot name="size" :msg="msg"></slot>
</div>
</template>
<script>
export default {
data(){
return{
msg:'300mL大小的杯子'
}
}
}
</script>
解構prop的寫法
下面寫法等同上面
//父級
<template>
<div>
<cup>
<div slott="size" slot-scope="{msg}">
{{msg}}
</div>
</cup>
</div>
</template>
上述是vue2.6之前的版本,之後vue官方廢棄了上面的語法,改爲v-solt來代替,然後大家就想知道,區別在哪呢
首先就是 用一個指令合併了solt 和solt-scope2個attribute,寫法更加簡潔,其次就是語義化更明顯
2.6之前的寫法會出現作用域混淆的問題
例:
<one>
<two slot-scope="one"> //接受到的作用域,是外層one組件的,而不是當前組件two
<three slot-scope="two">
<template slot-scope="three">
{{ one }} {{ two }} {{ three }}
</template>
</three>
</two>
</one>
如上述代碼一層子組件時,你能清晰的看清作用域是哪一個組件的,但多層嵌套後,每一層接收的作用域是外層組件的而不是當前組件的,這樣,就會不清晰,所以vue希望能實現,當前組件,接受當前組件的作用域
於是就有了v-solt 下面是改良後的代碼,是否更加的清晰了
<one v-slot="one">
<twotwo v-slot="two"> //接收到的作用域爲當前two組件的
<three v-slot="three">
{{ one }} {{ two }} {{ three }}
</three>
</bar>
</one>
如果沒看懂 那麼下面來闡述,v-solt的使用變化,
v-solt 默認插槽
和原來不同便是,原來的solt屬性可以定義在任何元素上,現在v-solt只能是template元素上,只有一種額外情況,就是獨佔默認插槽,我們先看常規情況。v-slot:default這種就是具名的寫法
父組件
<template>
<item >
<template v-slot:default> // v-slot:default可以不加,只能定義在template上
<div>裝一杯牛奶</div>
</template>
<item>
</template>
//item子組件
<template>
<div>
<slot ></slot>//默認插槽
<h1>
我是杯子
</h1>
</div>
</template>
未具名的solt 元素,自動默認名爲default 你可以不寫,當然如果你要看的更清晰,
獨佔默認插槽
提供內容只有默認插槽,上述就滿足此條件,所以我們可以這樣寫
父組件
<template>
<item v-slot:default> //v-slot:default可以不加
<div>裝一杯牛奶</div>
<item>
</template>
//item子組件
<template>
<div>
<slot ></slot>//默認插槽
<h1>
我是杯子
</h1>
</div>
</template>
v-solt具名插槽
//父級
<template>
<div>
<layout>
<template v-slot:header>//v-slot指令使用插槽
<div >頭部標題</div>
</template>
<div >顯示的默認內容</div>
<!--
或者
<template v-slot:default>
<div >顯示的默認內容</div>
</template>
-->
<template v-slot:footer>
<div >尾部</div>
</template>
</layout>
</div>
</template>
//layout子組件
<template>
<div>
<layout>
<h1>layout子組件</h1>
<slot name="header"></slot> //這種就叫具名插槽
<slot></slot> //如果不指定名字,就會將模板中未匹配到的內容渲染到默認插槽中,這裏爲顯示的內容
<slot name="footer"></slot>
</layout>
</div>
</template>
v-solt作用域插槽
這是改動最大地方
//父級
<template>
<div>
<cup>
<template v-slot:default="data"> //具名寫法
<div>
{{data.msg}}
</div>
</template>
<!--
或者
<template v-slot="data">
<div > {{data.msg}} </div>
</template>
-->
</cup>
</div>
</template>
//cup子組件
<template>
<div>
<slot name="size" :msg="msg"></slot >
</div>
</template>
<script>
export default {
data(){
return{
msg:'300mL大小的杯子'
}
}
}
</script>
當爲獨佔默認插槽時,v-solt可以省略default不寫
注意默認插槽的縮寫語法不能和具名插槽混用,因爲它會導致作用域不明確下面是官方的例子
<!-- 無效,會導致警告 -->
<current-user v-slot="slotProps">
{{ slotProps.user.firstName }}
<template v-slot:other="otherSlotProps">
slotProps is NOT available here
</template>
</current-user>
所以當出現多個插槽的時候,請使用完整的基於template 的語法
解構props的寫法
這裏使用上面cup組件的例子
<template>
<div>
<cup>
<template v-slot:default="{msg}"> //解構
<div>
{{msg}}
</div>
</template>
</cup>
</div>
</template>
v-slot 的解構還提供 重命名的寫法
<template>
<div>
<cup>
<template v-slot:default="{msg : size}"> //別名
<div>
{{size}}
</div>
</template>
</cup>
</div>
</template>
動態插槽名
v-slot 支持2.6的動態參數寫法
<layout>
<template v-slot:[attributeName]>
...
</template>
</layout>
這裏的 attributeName
會被作爲一個 JavaScript 表達式進行動態求值,求得的值將會作爲最終的參數來使用。例如,如果你的 Vue 實例有一個 data
property attributeName
,其值爲 "header"
,那麼這個綁定將等價於 v-slot:header
。
插槽的縮寫
2.6後插槽 可以把參數之前的所有內容 (v-slot:
) 替換爲字符 #
。例如 v-slot:header
可以被重寫爲 #header
v-slot:後面必須有值,不可寫成#="{data}"
<template>
<div>
<cup>
<template #default="msg">
<div>
{{size}}
</div>
</template>
</cup>
</div>
</template>