Appearance
插槽(Slot)
假設有一輛普通的汽車內飾,它包括座椅、方向盤、控制面板等元素。更換這輛汽車的內飾讓汽車看起來與眾不同。可以解釋插槽思想:
- 座椅插槽:不同顏色、材質的座椅套件插入這個插槽中。例如:插入紅色皮革套件,使座椅變成紅色;插入藍色絲綢套件,使座椅變成藍色。
- 方向盤插槽:在方向盤插槽中插入不同樣式的方向盤套,例如:木質紋理、碳纖維材質等,以改變方向盤的外觀。
- 內飾顏色插槽:在內飾顏色插槽中插入不同的顏色選項,例如黑色、銀色或金色,以改變整個內飾的主要色調。
vue
<!-- parent component -->
<template>
<FancyButton>
<!-- 把文字作為 slot content 插入 FancyButton -->
點我!
</FancyButton>
</template>
<!-- parent component -->
<template>
<FancyButton>
<!-- 把文字作為 slot content 插入 FancyButton -->
點我!
</FancyButton>
</template>
vue
<!-- child component -->
<template>
<button>
<!-- 沒有指定名稱就是 default slot -->
<slot>
<!-- 如果父元件沒有指定 slot 的內容,會顯示預設值 -->
預設值
</slot>
</button>
</template>
<!-- child component -->
<template>
<button>
<!-- 沒有指定名稱就是 default slot -->
<slot>
<!-- 如果父元件沒有指定 slot 的內容,會顯示預設值 -->
預設值
</slot>
</button>
</template>
存取範圍
Expressions 存取範圍:
- 寫在 parent template 裡面的 expression 只可存取 parent scope
- 寫在 child template 裡面的 expression 只可存取 child scope
- 寫在 parent template 裡面待插入 slot 的語法只可存取 parent scope
具名插槽
html
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
html
<BaseLayout>
<!-- v-slot:header 把內容綁定到名稱為 header 的 slot -->
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<!-- 沒有包裹的內容預設會顯示在 default slot 裡面 -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<!-- #footer 把內容綁定到名稱為 footer 的 slot -->
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
<BaseLayout>
<!-- v-slot:header 把內容綁定到名稱為 header 的 slot -->
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<!-- 沒有包裹的內容預設會顯示在 default slot 裡面 -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<!-- #footer 把內容綁定到名稱為 footer 的 slot -->
<template #footer>
<p>Here's some contact info</p>
</template>
</BaseLayout>
動態插槽名稱
可以用程式動態指定內容要插在哪個 slot:
html
<base-layout>
<template v-slot:[dynamicSlotName]> ... </template>
<!-- with shorthand -->
<template #[dynamicSlotName]> ... </template>
</base-layout>
<base-layout>
<template v-slot:[dynamicSlotName]> ... </template>
<!-- with shorthand -->
<template #[dynamicSlotName]> ... </template>
</base-layout>
作用域插槽(scoped slot)
簡單說:為了讓 slot content 拿到 child 的內容,會讓 child 綁定屬性再做使用,有點像反向注入,在 UI Framework 的元件內大量被使用,必須了解這個才能讀 quasar、vuetify 等等框架的文件。
html
<!-- child -->
<div>
<slot :text="greetingMessage" :count="1"></slot>
</div>
<!-- child -->
<div>
<slot :text="greetingMessage" :count="1"></slot>
</div>
html
<!-- parent -->
<!-- child 綁定的所有屬性會變成一個物件,這裡把它命名 slotProps -->
<template v-slot="slotProps">
<!-- 這時候可以透過 slotProps 拿到子元件綁定的屬性 -->
{{ slotProps.text }} {{ slotProps.count }}
</template>
<!-- parent -->
<!-- child 綁定的所有屬性會變成一個物件,這裡把它命名 slotProps -->
<template v-slot="slotProps">
<!-- 這時候可以透過 slotProps 拿到子元件綁定的屬性 -->
{{ slotProps.text }} {{ slotProps.count }}
</template>
通常搭配解構賦值使用。
html
<!-- parent -->
<!-- 父元件只需要少數特定的屬性時,可透過解構賦值直接拿到特定屬性 -->
<template v-slot="{ text, count }">
<!-- 使用時不需每次都透過最上層 slotProps -->
{{ text }} {{ count }}
</template>
<!-- parent -->
<!-- 父元件只需要少數特定的屬性時,可透過解構賦值直接拿到特定屬性 -->
<template v-slot="{ text, count }">
<!-- 使用時不需每次都透過最上層 slotProps -->
{{ text }} {{ count }}
</template>
Summary
- 插槽可以有預設值。
- 插槽名稱
- 插槽名稱可以是字串或動態綁定。
- 沒有名稱的插槽稱為預設插槽
- 多個預設插槽父元件需按照順序插入。
- 插槽作用域
- 父元件插入插槽的內容只能存取父元件的狀態。
- 作用域插槽能讓子元件提供狀態給插槽內容使用。
- 作用域插槽取值常搭配解構賦值。