Vue 具名作用域插槽 (Named Scoped Slots) 詳解:打造頂級靈活的元件接口
在 Vue 的插槽系統中,具名插槽 解決了「在哪裡渲染」的問題,而作用域插槽解決了「用什麼資料渲染」的問題。當我們將兩者結合,就進化成了 具名作用域插槽,它允許您在一個元件中開放多個特定區域,並分別將內部的私有資料傳遞出來給父元件自定義。
核心觀念:雙劍合璧
具名作用域插槽的核心在於:子元件在不同的 <slot> 中綁定不同的屬性(Attributes),父元件則透過 v-slot:插槽名="資料物件" 的語法來接收。
- 具名 (Named):使用
name="xxx"標識位置。 - 作用域 (Scoped):使用
:data="value"進行屬性綁定。 - 父元件接收:使用
#name="{ data }"(解構寫法) 進行操作。
實作步驟
- 子元件定義:在特定的
<slot>標籤上同時設定 name 屬性與資料綁定。 - 父元件呼叫:使用
<template>標籤並指定插槽名稱。 - 接收參數:在
<template>標籤的v-slot指令中定義參數名稱(或進行解構)。 - 定義 UI: 利用接收到的資料決定該區塊的 HTML 結構。
實作範例:複雜資料清單
假設我們要開發一個 ProductList.vue 元件,它負責顯示產品列表,並開放「產品名稱」與「操作按鈕」兩個區塊給父元件自定義,且兩個區塊都需要存取目前的產品資料。
子元件:ProductList.vue
vue
<script setup>
const products = [
{ id: 1, name: "咖啡機", price: 5000, stock: 10 },
{ id: 2, name: "磨豆機", price: 2500, stock: 0 },
];
</script>
<template>
<div class="list-container">
<div v-for="item in products" :key="item.id" class="item-row">
<slot name="title" :item="item"> {{ item.name }} (預設) </slot>
<slot name="action" :item="item" :isOut="item.stock === 0">
<button>查看詳情</button>
</slot>
</div>
</div>
</template>父元件:App.vue
vue
<template>
<ProductList>
<template #title="{ item }">
<h3 style="color: blue;">{{ item.name }} - NT${{ item.price }}</h3>
</template>
<template #action="{ item, isOut }">
<button :disabled="isOut">
{{ isOut ? "補貨中" : `購買 (${item.stock})` }}
</button>
</template>
</ProductList>
</template>為什麼要使用具名作用域插槽?
極致的 UI 控制權
子元件負責繁瑣的邏輯,例如 v-for、API 請求、狀態判斷,父元件則能像「拼圖」一樣決定每個關鍵位置的長相。
避免元件臃腫
不需要透過無數的 props,例如 titleColor, showBuyButton 來控制 UI,直接開放插槽讓父元件處理最乾淨。
強大的複用性
同一個列表元件,在 A 頁面可以顯示為圖卡,在 B 頁面可以顯示為簡易表格,只需替換插槽內容。
注意事項
- 避免命名衝突:確保子元件中 slot 綁定的屬性名稱與父元件解構的變數名稱一致。
- 預設值的設置:建議在子元件的 slot 內部撰寫預設內容,以防父元件未傳入內容時頁面空無一物。
- 適度使用: 雖然靈活,但若一個元件有超過 5 個具名作用域插槽,可能會讓父元件的樣板變得過於複雜,此時應考慮是否需拆分元件。
