[Vue] Slot 是什麼? 怎麼用?
Slot 是一種內容分發(content distribution)的 API,中文翻譯為插槽,適合用在結構比較複雜,元件內容可以重複使用的地方。簡單說就是在 component 中可以預留空間,在父層再把內容放進去。
Outline:- 基本使用、後備內容 ( Basic Usage, Fallback Content )
- 編譯作用域 (Compilation Scope )
- 具名插槽 ( Named Slots )
- 作用域插槽 ( Scoped Slots )
- 解構插槽Prop ( Destructuring Slot Props )
- 具名插槽的縮寫 ( Named Slots Shorthand )
- 列表範例 ( Example )
基本使用、後備內容 (Basic Usage, Fallback Content)
基本使用 Basic Usage
一般的 Component 長這樣:
Vue.component("component-basic", {
template: "<div>我是一般的component</div>"
});
加上 slot
會長這樣:
Vue.component("component-slot", {
template:
"<div><slot></slot></div>"
});
<slot>
包起來的地方就是在父層使用這個 component 的時候可以塞內容的地方,舉例:
<template>
<component-slot>我是指定的內容</component-slot>
</template>
那麼就會編譯出:
<div>我是指定的內容</div>
後備內容 Fallback Content
後備內容就像是 backup plan,如果在父層沒有提供 slot
內容就會出現:
Vue.component("component-slot", {
template:
"<div><slot>我會在沒有內容的時候出現,指定的內容會長在這裡</slot></div>"
});
所以如果在父層使用這個 component 的時候沒有在裡面放內容:
<component-slot></component-slot>
後備內容就會被編譯出來:
<div>我會在沒有內容的時候出現,指定的內容會長在這裡</div>
編譯作用域 (Compilation Scope )
官方說法:父級模板裡的所有內容都是在父級作用域中編譯的;子模板裡的所有內容都是在子作用域中編譯的。
白話一點:父層的 data 父層才拿得到,子層的 data 子層才拿得到,舉例:
component 自己的 data 是 "haha”,父層的 data 是 “hehe”:
如果 component 要抓父層的 data 就抓不到了,會壞去
具名插槽
自 2.6.0 版本之後,以 slot 為 attribute 的語法已經被廢棄,如:
<template slot="header">
<h1>Here might be a page title</h1>
</template>
如果在一個 component 裡面需要多個 slot
,可以替 slot
取名字,舉例:
在這邊依序設定了四個 slot
分別為:header、content、default、footer,要注意這邊的 slot template 決定了內容的位置,且在父層使用的時候可以使用 template + v-slot 來指定要使用的 slot
:
<component-slot-name>
<template v-slot:footer>我要指定name是footer的slot內容</template>
<template v-slot:header>我要指定name是header的slot內容</template>
<template>我要指定沒有name(default)的slot內容</template>
<template v-slot:content>我要指定name是content的slot內容</template>
</component-slot-name>
在父層這邊使用的 slot
位置依序是 footer、header、default、content,渲染出來一樣是依照 slot template 的順序,如果 slot 沒有取名,則會默認為 default,沒有指定 v-slot 名稱的 template,也會當作是默認的 default slot 內容:
要注意v-slot
只能添加在<template>
上
作用域插槽 ( Scoped Slots )
自 2.6.0 版本之後,slot-scope 的用法也已經被廢棄,如:
<template slot="default" slot-scope="slotProps">
{{ slotProps.msg }}
</template>
讓父層在指定 slot
內容的時候可以指定需要的 component 的 data。
舉例:
在這邊 component 的 data 有一個 slotuser,在 template 中用了像是 props 的方式把 slotuser 拿去給 slot 使用,這樣在父層使用此 component 的時候就可以像是以下這樣將值取出來用:
<component-scoped v-slot:default="slotProps">
{{ slotProps.user.firstName }}
</component-scoped>
slotProps 是自定義的名稱,如果只有一個 slot 要使用, :default 可以省略,v-slot 也可以直接放在 component tag 上,如果有多個具名 slot 就不行,一樣要用 template 分開來寫
解構插槽Prop (Destructuring Slot Props)
官方提到 props 的原理是 將你的插槽內容包括在一個傳入單個參數的函數里:
function (slotProps) { // 插槽内容 }
所以插槽 props 也可以用 ES6 解構的方式來傳入,舉例:
// 剛剛的
<component-scoped v-slot="slotProps">
{{ slotProps.user.firstName }}
</component-scoped>// 也可以直接等於
<component-scoped v-slot="{ user }">解構:{{ user.firstName }}</component-scoped>
// 或
<component-scoped v-slot="{ user:info }">解構:{{ info.firstName }}</component-scoped>
具名插槽的縮寫 ( Named Slots Shorthand )
和 v-on
, v-bind
一樣,v-slot
也有縮寫,替換符是 #
,舉例:
// 剛剛的
<template v-slot:footer>name 是 footer 的 slot 內容</template>// 可以變成
<template #footer>name 是 footer 的 slot 內容</template>
如果是 default 的話,一樣要寫出 #default
,如果需要使用 props的話:
<component-scoped #default="{ user }">解構:{{ user.firstName }}</component-scoped>
列表範例
使用 slot 結合 props 動態生成列表是很常見的應用,這邊做一個簡單的列表試試看:
就可以成功印出了 🏊🏊🏊
上述的所有範例都有在這邊:Demo Code
內容若有任何錯誤,歡迎留言交流指教! 🐬
ref
Slots-Vue.js