Vue 動態插槽 (Dynamic Slots) 完全指南:實作具備極致彈性的元件
動態插槽允許我們使用 JavaScript 變數 來決定要將內容插入哪一個插槽?透過方括號 [] 語法,我們可以根據邏輯、資料或 API 回傳的結果,動態地改變插槽名稱,讓元件的擴展性達到最高水準。
為什麼要使用動態插槽
在 Vue 的開發旅程中,我們已經學會了 基礎插槽、具名插槽 與 作用域插槽。然而,當您面對 高度通用型 的元件,例如:動態表單、可配置的數據表格時,插槽的名稱可能無法在撰寫程式碼時寫死。這時,動態插槽 (Dynamic Slots) 就是您的終極解決方案。
核心觀念:動態名稱綁定
動態插槽的核心在於 v-slot 的參數可以使用動態變數。其語法規則如下:
- 標準語法:
v-slot:[slotName]。 - 縮寫語法:
#[slotName]。
當 slotName 的值改變時,Vue 會自動更新內容注入的位置。這在處理根據配置生成的元件時非常強大。
如何在 Vue 中實作動態插槽?
子元件:準備接收動態內容
子元件只需要像平常一樣定義多個具名插槽,或者根據資料循環生成插槽。
<template>
<div class="dynamic-card">
<div class="header">
<slot name="header">預設標題</slot>
</div>
<div class="content">
<slot name="main"></slot>
<slot name="footer"></slot>
</div>
</div>
</template>父元件:使用變數決定插槽位置
父元件透過變數來切換內容要出現在哪一個插槽。
<script setup>
import { ref } from "vue";
import DynamicCard from "@/components/DynamicCard.vue";
// 動態名稱變數
const currentSlot = ref("main");
// 切換插槽的邏輯
const toggleSlot = () => {
currentSlot.value = currentSlot.value === "main" ? "footer" : "main";
};
</script>
<template>
<div>
<button @click="toggleSlot">切換渲染位置</button>
<p>目前渲染位置:{{ currentSlot }}</p>
<DynamicCard>
<template #[currentSlot]>
<div class="highlight">我是被動態傳入的內容!</div>
</template>
</DynamicCard>
</div>
</template>這裡的 currentSlot 是一個 ref,因此按下按鈕改變它的值時,插槽內容會立刻搬到另一個位置。
實戰場景:依配置檔產生欄位
動態插槽真正的價值在於 搭配 v-for 依設定批次產生插槽。以資料表格為例,欄位由設定檔決定,而每個欄位都開放給父元件自訂:
<!-- 子元件:DataTable.vue -->
<script setup>
const props = defineProps({
columns: { type: Array, required: true },
rows: { type: Array, required: true },
});
</script>
<template>
<table>
<tbody>
<tr v-for="row in rows" :key="row.id">
<td v-for="col in columns" :key="col.key">
<!-- 依欄位 key 產生具名插槽,並把該列資料傳出去 -->
<slot :name="col.key" :row="row">{{ row[col.key] }}</slot>
</td>
</tr>
</tbody>
</table>
</template><!-- 父元件:只覆寫想客製的欄位 -->
<template>
<DataTable :columns="columns" :rows="rows">
<template #price="{ row }">
<strong>NT${{ row.price }}</strong>
</template>
</DataTable>
</template>子元件的 :name="col.key" 讓插槽名稱由資料決定,欄位增減時 兩邊的模板都不需要修改。這裡同時用上了 作用域插槽 把該列資料傳給父元件,也就是 具名作用域插槽 的組合。
為什麼要使用動態插槽?
極致的元件抽象化
當您開發中台系統或元件庫時,還無法預期使用者會定義多少個區域。動態插槽讓您能根據配置檔(JSON)來生成 UI。
減少冗餘程式碼
避免在模板中使用大量的 v-if / v-else-if 來判斷該渲染哪一個插槽。
動態版面配置切換
適合用於需要即時改變內容分佈的場景,例如:可自定義面板位置的儀表板。
注意事項
- 名稱限制:動態插槽名稱若為
null,則該插槽會被移除。避免使用非字串類型的值。 - 語法約束:方括號內不可包含空格或引號(如
#[ 'my' + slot ]是無效的)。若有複雜邏輯,請先在computed計算好名稱。 - 對不上就不渲染:名稱拼錯或子元件沒有這個插槽時,內容會靜靜地消失且不會報錯,除錯時請先確認變數的實際值。
- 效能考量:雖然 Vue 處理動態插槽非常高效,但過度頻繁地切換插槽名稱可能會導致元件頻繁重新渲染,需注意效能平衡。
常見問題
動態插槽的語法怎麼寫?
把插槽名稱換成方括號包住的變數即可,標準寫法是 v-slot:[slotName],縮寫是 #[slotName]。變數的值改變時,內容就會被搬到對應名稱的插槽。
方括號裡可以寫運算式嗎?
只能放簡單的變數,不可包含空格或引號。需要組字串或條件判斷時,請先用 computed 算好名稱再放進方括號。
動態插槽名稱對不上任何插槽會怎樣?
該段內容不會被渲染,畫面上就像沒寫一樣,也不會拋出錯誤。除錯時可以先把變數的值印出來確認拼字是否正確。
可以用 v-for 一次產生多個插槽嗎?
可以,這是動態插槽最實用的場景。子元件用 v-for 依欄位設定產生具名插槽,父元件也用動態名稱填入內容,欄位增減時模板都不用改。
動態插槽和條件插槽有什麼不同?
動態插槽決定內容要放進 哪一個位置,條件插槽 決定某個區塊 要不要渲染。前者處理位置,後者處理有無,兩者也可以搭配使用。