[Vue] Slot 是什麼? 怎麼用?

itsems
itsems_frontend
Published in
7 min readMay 17, 2020
Photo by Hayley Maxwell on Unsplash

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

--

--

itsems
itsems_frontend

Stay Close to Anything that Makes You Glad You are Alive.