跳至主要内容

[vue] Vue Slot 用法

說明

介紹一下 Vue 的 slot 用法

slot

如果想要傳送子元素到另外一個 Component,我們可以使用 <slot></slot>,這就跟 React 的 children 相似。

我們在 AppCourseCard 底下傳入一個 p 元素,並且在 AppCourseCard 內,使用 <slot></slot>

AppCourse.vue
<template>
<AppCourseCard>
<p>Hello World</p>
</AppCourseCard>
</template>

<script setup>
import AppCourseCard from './AppCourseCard.vue'
</script>
AppCourseCard.vue
<template>
<h1>AppCourseCard</h1>
<div>
<slot></slot>
</div>
</template>

可以看到,我們的 <slot></slot> 元素在畫面上被渲染 p 元素。

Image

slot 預設值

如果今天 Component 沒有傳入任何的子元素,我們也可以給 slot 預設值。

AppCourse.vue
<template>
<AppCourseCard></AppCourseCard>
</template>

<script setup>
import AppCourseCard from './AppCourseCard.vue'
</script>

AppCourseCard.vue
<template>
<h1>AppCourseCard</h1>
<div>
<slot>
<b>沒有傳入子元素</b>
</slot>
</div>
</template>

Image

使用多個 slot

如果要使用多個 slot 的話,可以使用 # 關鍵字,相當於使用 v-slot

AppCourse.vue
<template>
<AppCourseCard>
<template #title>
<h2>我是 v-slot title</h2>
</template>
<template #description>
<p>我是</p>
<p>v-slot</p>
<p>description</p>
</template>
</AppCourseCard>
</template>

<script setup>
import AppCourseCard from './AppCourseCard.vue'
</script>

然後在 Component 的 slot 使用 name 來接收值

AppCourseCard.vue
<template>
<h1>AppCourseCard</h1>
<div>
<slot name="title"></slot>
</div>
<div>
<slot name="description"></slot>
</div>
</template>

Image

父元件 使用 子元件 的屬性

把 slot 放在子元件v-for

AppCourseCard.vue
<template>
<div v-for="animal in animals" :key="animal.id">
<slot />
<hr />
</div>
</template>

<script setup>
import { ref } from 'vue'
const animals = ref([
{
id: crypto.randomUUID(),
name: 'tiger'
},
{
id: crypto.randomUUID(),
name: 'panda'
},
{
id: crypto.randomUUID(),
name: 'bird'
}
])
</script>

父元件使用子元件的屬性,很明顯的會出現錯誤,因為在父元件 AppCourse內,並沒有定義 animal

AppCourse.vue
<template>
<AppCourseCard>
<p>id : {{ animal.id }}</p>
<p>name : {{ animal.name }}</p>
</AppCourseCard>
</template>

<script setup>
import AppCourseCard from './AppCourseCard.vue'
</script>

現在在 AppCourseCard 中,修改 slot 的程式碼,在 slot 中將 animal 動態綁定。

AppCourseCard.vue
<template>
<div v-for="animal in animals" :key="animal.id">
<slot :animal="animal" />
<hr />
</div>
</template>

<script setup>
import { ref } from 'vue'
const animals = ref([
{
id: crypto.randomUUID(),
name: 'tiger'
},
{
id: crypto.randomUUID(),
name: 'panda'
},
{
id: crypto.randomUUID(),
name: 'bird'
}
])
</script>

之後在 AppCourse 使用 template 並搭配 v-slot(簡寫為 #),取得子元件的 props 即可。

AppCourse.vue
<template>
<AppCourseCard>
<template #default="props">
<p>id : {{ props.animal.id }}</p>
<p>name : {{ props.animal.name }}</p>
</template>
</AppCourseCard>
</template>

<script setup>
import AppCourseCard from './AppCourseCard.vue'
</script>

這樣寫也可以,直接將 template 移除,並直接在 v-slot 內進行解構。

AppCourse.vue
<template>
<AppCourseCard v-slot="{ animal }">
<p>id : {{ animal.id }}</p>
<p>name : {{ animal.name }}</p>
</AppCourseCard>
</template>

<script setup>
import AppCourseCard from './AppCourseCard.vue'
</script>