Skip to content

Vue 動態插槽 (Dynamic Slots) 完全指南:實作具備極致彈性的元件

Vue 3 動態插槽:#[slotName] 語法

動態插槽允許我們使用 JavaScript 變數 來決定要將內容插入哪一個插槽?透過方括號 [] 語法,我們可以根據邏輯、資料或 API 回傳的結果,動態地改變插槽名稱,讓元件的擴展性達到最高水準。

為什麼要使用動態插槽

在 Vue 的開發旅程中,我們已經學會了 基礎插槽具名插槽作用域插槽。然而,當您面對 高度通用型 的元件,例如:動態表單、可配置的數據表格時,插槽的名稱可能無法在撰寫程式碼時寫死。這時,動態插槽 (Dynamic Slots) 就是您的終極解決方案。

核心觀念:動態名稱綁定

動態插槽的核心在於 v-slot 的參數可以使用動態變數。其語法規則如下:

  • 標準語法v-slot:[slotName]
  • 縮寫語法#[slotName]

當 slotName 的值改變時,Vue 會自動更新內容注入的位置。這在處理根據配置生成的元件時非常強大。

如何在 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>

父元件:使用變數決定插槽位置

父元件透過變數來切換內容要出現在哪一個插槽。

vue
<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 依設定批次產生插槽。以資料表格為例,欄位由設定檔決定,而每個欄位都開放給父元件自訂:

vue
<!-- 子元件: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>
vue
<!-- 父元件:只覆寫想客製的欄位 -->
<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 依欄位設定產生具名插槽,父元件也用動態名稱填入內容,欄位增減時模板都不用改。

動態插槽和條件插槽有什麼不同?

動態插槽決定內容要放進 哪一個位置條件插槽 決定某個區塊 要不要渲染。前者處理位置,後者處理有無,兩者也可以搭配使用。

延伸閱讀