前言
Vue.js 提供了強大的插槽(slot)功能,讓父組件能靈活地將內容傳遞給子組件。本文將介紹四種插槽的基本用法。
插槽(Slots)
插槽是 Vue 中最基本的使用方式,允許父組件在子組件中插入特定內容,如果插槽的內容只有一個則不用填寫 slot 名稱。
父組件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template> <div> <h1>這是父組件</h1> <hr /> <SlotComponent> <p>這段內容將被插入到子組件的 slot 中。</p> </SlotComponent> </div> </template>
<script> import SlotComponent from '@/components/SlotComponent.vue';
export default { components: { SlotComponent, }, }; </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <template> <div> <h1>這是父組件</h1> <hr /> <SlotComponent> <p>這段內容將被插入到子組件的 slot 中。</p> </SlotComponent> </div> </template>
<script> import { defineComponent } from 'vue' import SlotComponent from '@/components/SlotComponent.vue'
export default defineComponent({ components: { SlotComponent, }, }) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| <template> <div> <h1>這是父組件</h1> <hr /> <SlotComponent> <p>這段內容將被插入到子組件的 slot 中。</p> </SlotComponent> </div> </template>
<script setup> import SlotComponent from '@/components/SlotComponent.vue' </script>
|
子組件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <template> <div> <h2>這是子組件</h2>
<slot></slot> </div> </template>
<script> export default { name: 'SlotComponent', }; </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <div> <h2>這是子組件</h2>
<slot></slot> </div> </template>
<script> import { defineComponent } from 'vue'
export default defineComponent({ name: 'SlotComponent', }) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <template> <div> <h2>這是子組件</h2>
<slot></slot> </div> </template>
<script setup> defineOptions({ name: 'SlotComponent', }) </script>
|

具名插槽(Named slots)
具名插槽允許子組件定義多個插槽並指定名稱,這樣可以增強父組件在使用時的靈活性。
在 Vue 中,v-slot 可以縮寫為 #,後面接插槽的名稱(即 name 屬性),例如:#header。
父組件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <template> <div> <h1>這是父組件</h1> <hr /> <SlotComponent> <template v-slot:header> <h3>我是 header</h3> </template>
<p>我是內容區塊</p>
<template v-slot:footer> <p>我是 footer</p> </template> </SlotComponent> </div> </template>
<script> import SlotComponent from '@/components/SlotComponent.vue';
export default { name: 'ParentComponent', components: { SlotComponent, }, }; </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <template> <div> <h1>這是父組件</h1> <hr /> <SlotComponent> <template #header> <h3>我是 header</h3> </template>
<p>我是內容區塊</p>
<template #footer> <p>我是 footer</p> </template> </SlotComponent> </div> </template>
<script> import { defineComponent } from 'vue' import SlotComponent from '@/components/SlotComponent.vue'
export default defineComponent({ name: 'ParentComponent', components: { SlotComponent, }, }) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <div> <h1>這是父組件</h1> <hr /> <SlotComponent> <template #header> <h3>我是 header</h3> </template>
<p>我是內容區塊</p>
<template #footer> <p>我是 footer</p> </template> </SlotComponent> </div> </template>
<script setup> import SlotComponent from '@/components/SlotComponent.vue' </script>
|
子組件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <template> <div> <h2>這是子組件</h2> <slot name="header"></slot> <slot></slot> <slot name="footer"></slot> </div> </template>
<script> export default { name: 'SlotComponent', }; </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <div> <h2>這是子組件</h2> <slot name="header"></slot> <slot></slot> <slot name="footer"></slot> </div> </template>
<script> import { defineComponent } from 'vue'
export default defineComponent({ name: 'SlotComponent', }) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <template> <div> <h2>這是子組件</h2> <slot name="header"></slot> <slot></slot> <slot name="footer"></slot> </div> </template>
<script setup> defineOptions({ name: 'SlotComponent', }) </script>
|

作用域插槽(Scoped Slots)
作用域插槽允許父組件從子組件獲取數據,並將其傳遞到插槽中,實現根據子組件狀態或屬性動態渲染內容。
父組件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <template> <div> <SlotComponent v-slot:default="{ message }"> <p>{{ message }}</p> </SlotComponent> </div> </template>
<script> import SlotComponent from '@/components/SlotComponent.vue';
export default { components: { SlotComponent, }, }; </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <div> <SlotComponent v-slot:default="{ message }"> <p>{{ message }}</p> </SlotComponent> </div> </template>
<script> import { defineComponent } from 'vue' import SlotComponent from '@/components/SlotComponent.vue'
export default defineComponent({ components: { SlotComponent, }, }) </script>
|
1 2 3 4 5 6 7 8 9 10 11
| <template> <div> <SlotComponent v-slot:default="{ message }"> <p>{{ message }}</p> </SlotComponent> </div> </template>
<script setup> import SlotComponent from '@/components/SlotComponent.vue' </script>
|
子組件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <template> <div> <slot :message="childMessage"></slot> </div> </template>
<script> export default { data() { return { childMessage: '來自子組件的消息', }; }, }; </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <div> <slot :message="childMessage"></slot> </div> </template>
<script> import { defineComponent, ref } from 'vue'
export default defineComponent({ setup() { const childMessage = ref('來自子組件的消息') return { childMessage } }, }) </script>
|
1 2 3 4 5 6 7 8 9 10 11
| <template> <div> <slot :message="childMessage"></slot> </div> </template>
<script setup> import { ref } from 'vue'
const childMessage = ref('來自子組件的消息') </script>
|

動態插槽(Dynamic Slots)
動態插槽允許根據條件渲染不同的插槽,適用於需要在同一組件中根據狀態顯示不同內容的情況。
父組件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <template> <div> <h1>這是父組件</h1> <hr /> <button @click="toggleSlot">切換插槽</button> <SlotComponent :currentSlot="currentSlot"> <template v-slot:slot1> <p>這是第一個插槽的內容。</p> </template> <template v-slot:slot2> <p>這是第二個插槽的內容。</p> </template> </SlotComponent> </div> </template>
<script> import SlotComponent from '@/components/SlotComponent.vue';
export default { components: { SlotComponent, }, data() { return { currentSlot: 'slot1', }; }, methods: { toggleSlot() { this.currentSlot = this.currentSlot === 'slot1' ? 'slot2' : 'slot1'; }, }, }; </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <template> <div> <h1>這是父組件</h1> <hr /> <button @click="toggleSlot">切換插槽</button> <SlotComponent :currentSlot="currentSlot"> <template #slot1> <p>這是第一個插槽的內容。</p> </template> <template #slot2> <p>這是第二個插槽的內容。</p> </template> </SlotComponent> </div> </template>
<script> import { defineComponent, ref } from 'vue' import SlotComponent from '@/components/SlotComponent.vue'
export default defineComponent({ components: { SlotComponent, }, setup() { const currentSlot = ref('slot1')
const toggleSlot = () => { currentSlot.value = currentSlot.value === 'slot1' ? 'slot2' : 'slot1' }
return { currentSlot, toggleSlot, } }, }) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <template> <div> <h1>這是父組件</h1> <hr /> <button @click="toggleSlot">切換插槽</button> <SlotComponent :currentSlot="currentSlot"> <template #slot1> <p>這是第一個插槽的內容。</p> </template> <template #slot2> <p>這是第二個插槽的內容。</p> </template> </SlotComponent> </div> </template>
<script setup> import { ref } from 'vue' import SlotComponent from '@/components/SlotComponent.vue'
const currentSlot = ref('slot1')
const toggleSlot = () => { currentSlot.value = currentSlot.value === 'slot1' ? 'slot2' : 'slot1' } </script>
|
子組件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <div> <slot :name="currentSlot"></slot> </div> </template>
<script> export default { props: { currentSlot: { type: String, required: true, }, }, }; </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <div> <slot :name="currentSlot"></slot> </div> </template>
<script> import { defineComponent } from 'vue'
export default defineComponent({ props: { currentSlot: { type: String, required: true, }, }, }) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <template> <div> <slot :name="currentSlot"></slot> </div> </template>
<script setup> defineProps({ currentSlot: { type: String, required: true, }, }) </script>
|

總結
透過上述範例,我們可以看到 Vue 的插槽功能如何有效提升組件的靈活性。無論是選擇哪個插槽,都能讓開發者在組件之間輕鬆傳遞內容,實現更複雜的 UI 結構。