Vue 中 slot 的使用方法
在 Vue 組件化開發中,slot(插槽)就像組件預留的 “靈活接口”,讓父組件能向子組件的指定位置插入自定義內容,既保留了子組件的結構複用,又賦予了內容定製的靈活性,避免了組件過於僵硬。無論是簡單的文本插入,還是複雜的組件嵌套,slot 都能輕鬆應對,是組件複用與定製的核心工具。
最基礎的是默認插槽,子組件中預留一個未命名的插槽,父組件在使用子組件時,直接在標籤內部寫入的內容,都會被渲染到這個插槽位置。比如一個通用的卡片組件,需要父組件自定義卡片內容:
<!-- 子組件 Card.vue -->
<template>
<div class="card">
<div class="card-header">
<h3>通用卡片</h3>
</div>
<!-- 默認插槽:父組件內容會插入這裏 -->
<slot></slot>
<div class="card-footer">
<button>操作按鈕</button>
</div>
</div>
</template>
<!-- 父組件 App.vue -->
<template>
<div class="app">
<h2>默認插槽示例</h2>
<!-- 向默認插槽插入自定義內容 -->
<Card>
<p>這是父組件插入的卡片內容</p>
<p>可以是文本、標籤或其他組件</p>
<img src="https://picsum.photos/200/100" alt="示例圖片">
</Card>
</div>
</template>
<script setup>
import Card from './Card.vue'
</script>
這裏子組件的<slot>標籤就是默認插槽的入口,父組件在<Card>標籤內寫入的所有內容,都會替換<slot>的位置,既複用了卡片的頭部和底部結構,又實現了內容的自定義。
當子組件需要多個自定義區域時,就需要用到具名插槽。給每個插槽命名,父組件通過v-slot:插槽名(簡寫為#插槽名)指定內容插入的位置,精準控制不同區域的顯示:
<!-- 子組件 Layout.vue -->
<template>
<div class="layout">
<!-- 頭部插槽:命名為header -->
<slot name="header"></slot>
<!-- 主體插槽:命名為main -->
<slot name="main"></slot>
<!-- 底部插槽:命名為footer -->
<slot name="footer"></slot>
</div>
</template>
<!-- 父組件 App.vue -->
<template>
<div class="app">
<h2>具名插槽示例</h2>
<Layout>
<!-- 向header插槽插入內容 -->
<template #header>
<div class="layout-header">
<h3>頁面標題</h3>
<nav>導航菜單</nav>
</div>
</template>
<!-- 向main插槽插入內容 -->
<template #main>
<div class="layout-main">
<p>這是頁面的主要內容區域</p>
<Card>嵌套的卡片組件</Card>
</div>
</template>
<!-- 向footer插槽插入內容 -->
<template #footer>
<div class="layout-footer">
<p>版權信息 © 2024</p>
</div>
</template>
</Layout>
</div>
</template>
<script setup>
import Layout from './Layout.vue'
import Card from './Card.vue'
</script>
具名插槽讓子組件的多個自定義區域各司其職,父組件可以按需填充每個插槽的內容,尤其適合佈局類組件(如頭部、主體、底部的拆分),讓組件結構更清晰。
還有一種常用場景:父組件需要使用子組件內部的數據來渲染插槽內容,這時作用域插槽就能派上用場。子組件通過<slot>標籤的屬性傳遞數據,父組件接收後,結合這些數據定製內容:
<!-- 子組件 List.vue -->
<template>
<div class="list">
<ul>
<li v-for="(item, index) in list" :key="index">
<!-- 向父組件傳遞當前項數據item和索引index -->
<slot :item="item" :index="index"></slot>
</li>
</ul>
</div>
</template>
<script setup>
import { reactive } from 'vue'
// 子組件內部的數據
const list = reactive([
{ name: 'Vue', type: '框架' },
{ name: 'React', type: '框架' },
{ name: 'Angular', type: '框架' }
])
// 定義插槽傳遞的屬性(可選,用於類型提示)
defineProps({})
defineEmits({})
</script>
<!-- 父組件 App.vue -->
<template>
<div class="app">
<h2>作用域插槽示例</h2>
<!-- 接收子組件傳遞的插槽數據 -->
<List>
<template #default="slotProps">
<!-- 父組件使用子組件傳遞的item和index -->
<p>索引:{{ slotProps.index }} - 名稱:{{ slotProps.item.name }}({{ slotProps.item.type }})</p>
</template>
</List>
<!-- 解構插槽數據,寫法更簡潔 -->
<List>
<template #default="{ item, index }">
<p>第{{ index + 1 }}項:{{ item.name }} - 自定義顯示格式</p>
</template>
</List>
</div>
</template>
<script setup>
import List from './List.vue'
</script>
作用域插槽的核心是 “數據反向傳遞”:子組件將內部數據通過插槽屬性暴露給父組件,父組件接收後(可通過解構簡化寫法),根據這些數據定製渲染邏輯。這種方式既複用了子組件的列表渲染邏輯,又讓父組件能靈活控制每一項的顯示格式,常見於表格、列表等需要自定義項渲染的組件。
此外,插槽還支持設置默認內容,當父組件沒有給插槽傳遞內容時,默認內容會生效,提升組件的可用性:
<!-- 子組件 Button.vue -->
<template>
<button class="custom-btn">
<!-- 默認內容:父組件未傳遞時顯示“默認按鈕” -->
<slot>默認按鈕</slot>
</button>
</template>
<!-- 父組件 App.vue -->
<template>
<div class="app">
<h2>插槽默認內容示例</h2>
<!-- 未傳遞內容,顯示默認文本 -->
<Button></Button>
<!-- 傳遞自定義內容,替換默認值 -->
<Button>提交表單</Button>
</div>
</template>
slot 的設計讓 Vue 組件既保持了高複用性,又不失靈活性。默認插槽滿足簡單自定義需求,具名插槽解決多區域定製問題,作用域插槽實現數據聯動渲染,合理運用這三種插槽類型,能讓組件的通用性和擴展性大大提升,是 Vue 組件化開發中不可或缺的重要技巧。