Skip to content

组件插槽

组件插槽是Vue3中的一个重要特性,它允许你在组件中定义可替换的内容区域。本章节将详细介绍Vue3中组件插槽的使用方法,包括默认插槽、具名插槽和作用域插槽。

什么是插槽?

插槽是Vue3中用于向组件传递内容的机制,它允许你在组件的模板中定义一些占位符,然后在使用组件时填充这些占位符。

默认插槽

1. 基本用法

默认插槽是最简单的插槽类型,它允许你向组件传递任意内容:

vue
<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent>
      <p>Hello from parent</p>
      <button>Click me</button>
    </ChildComponent>
  </div>
</template>

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

<!-- ChildComponent.vue -->
<template>
  <div class="child">
    <h1>Child Component</h1>
    <slot></slot>
  </div>
</template>

2. 默认内容

你可以为插槽提供默认内容,当父组件没有提供内容时会显示默认内容:

vue
<template>
  <div class="child">
    <h1>Child Component</h1>
    <slot>
      <p>Default content</p>
    </slot>
  </div>
</template>

具名插槽

1. 基本用法

具名插槽允许你在组件中定义多个插槽,并为每个插槽指定一个名称:

vue
<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent>
      <template #header>
        <h2>Header content</h2>
      </template>
      <template #main>
        <p>Main content</p>
      </template>
      <template #footer>
        <p>Footer content</p>
      </template>
    </ChildComponent>
  </div>
</template>

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

<!-- ChildComponent.vue -->
<template>
  <div class="child">
    <div class="header">
      <slot name="header"></slot>
    </div>
    <div class="main">
      <slot name="main"></slot>
    </div>
    <div class="footer">
      <slot name="footer"></slot>
    </div>
  </div>
</template>

<style scoped>
.child {
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 20px;
}

.header {
  background-color: #f0f0f0;
  padding: 10px;
  margin-bottom: 10px;
}

.main {
  padding: 10px;
  margin-bottom: 10px;
}

.footer {
  background-color: #f0f0f0;
  padding: 10px;
}
</style>

2. 简写语法

你可以使用简写语法 # 来表示具名插槽:

vue
<template>
  <div>
    <ChildComponent>
      <template #header>
        <h2>Header content</h2>
      </template>
      <template #main>
        <p>Main content</p>
      </template>
      <template #footer>
        <p>Footer content</p>
      </template>
    </ChildComponent>
  </div>
</template>

作用域插槽

1. 基本用法

作用域插槽允许子组件向父组件传递数据:

vue
<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent>
      <template #default="slotProps">
        <p>Name: {{ slotProps.name }}</p>
        <p>Age: {{ slotProps.age }}</p>
      </template>
    </ChildComponent>
  </div>
</template>

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

<!-- ChildComponent.vue -->
<template>
  <div class="child">
    <h1>Child Component</h1>
    <slot :name="user.name" :age="user.age"></slot>
  </div>
</template>

<script setup>
import { reactive } from 'vue'

const user = reactive({
  name: 'John',
  age: 25
})
</script>

2. 解构赋值

你可以使用解构赋值来简化作用域插槽的使用:

vue
<template>
  <div>
    <ChildComponent>
      <template #default="{ name, age }">
        <p>Name: {{ name }}</p>
        <p>Age: {{ age }}</p>
      </template>
    </ChildComponent>
  </div>
</template>

3. 具名作用域插槽

你可以为作用域插槽指定名称:

vue
<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent>
      <template #user="{ name, age }">
        <p>Name: {{ name }}</p>
        <p>Age: {{ age }}</p>
      </template>
      <template #item="{ item }">
        <p>Item: {{ item.name }}</p>
      </template>
    </ChildComponent>
  </div>
</template>

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

<!-- ChildComponent.vue -->
<template>
  <div class="child">
    <h1>Child Component</h1>
    <slot name="user" :name="user.name" :age="user.age"></slot>
    <slot name="item" :item="item"></slot>
  </div>
</template>

<script setup>
import { reactive, ref } from 'vue'

const user = reactive({
  name: 'John',
  age: 25
})

const item = ref({
  name: 'Item 1'
})
</script>

动态插槽名

你可以使用动态插槽名来动态选择插槽:

vue
<template>
  <div>
    <ChildComponent>
      <template #[dynamicSlotName]>
        <p>Dynamic slot content</p>
      </template>
    </ChildComponent>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'

const dynamicSlotName = ref('header')
</script>

插槽的最佳实践

1. 合理使用插槽

  • 默认插槽:适合简单的内容传递
  • 具名插槽:适合复杂的布局,如头部、主体、底部等
  • 作用域插槽:适合需要子组件数据的场景

2. 保持插槽的清晰性

  • 为具名插槽使用语义化的名称
  • 为作用域插槽的 props 使用清晰的命名
  • 避免过度使用插槽,保持组件的简洁性

3. 插槽的性能考虑

  • 避免在插槽中使用复杂的表达式
  • 对于频繁变化的内容,考虑使用响应式数据
  • 合理使用默认内容,减少不必要的渲染

插槽的使用场景

1. 布局组件

vue
<template>
  <div class="layout">
    <header class="header">
      <slot name="header"></slot>
    </header>
    <main class="main">
      <slot></slot>
    </main>
    <footer class="footer">
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<style scoped>
.layout {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.header {
  background-color: #333;
  color: white;
  padding: 10px;
}

.main {
  flex: 1;
  padding: 20px;
}

.footer {
  background-color: #333;
  color: white;
  padding: 10px;
  text-align: center;
}
</style>

2. 列表组件

vue
<template>
  <div class="list">
    <h2>{{ title }}</h2>
    <ul>
      <li v-for="item in items" :key="item.id">
        <slot name="item" :item="item"></slot>
      </li>
    </ul>
  </div>
</template>

<script setup>
defineProps({
  title: String,
  items: Array
})
</script>

<style scoped>
.list {
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 20px;
}

ul {
  list-style: none;
  padding: 0;
}

li {
  padding: 10px;
  border-bottom: 1px solid #eee;
}

li:last-child {
  border-bottom: none;
}
</style>

3. 卡片组件

vue
<template>
  <div class="card">
    <div class="card-header">
      <slot name="header"></slot>
    </div>
    <div class="card-body">
      <slot></slot>
    </div>
    <div class="card-footer">
      <slot name="footer"></slot>
    </div>
  </div>
</template>

<style scoped>
.card {
  border: 1px solid #ccc;
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 20px;
}

.card-header {
  background-color: #f0f0f0;
  padding: 15px;
  border-bottom: 1px solid #ccc;
}

.card-body {
  padding: 15px;
}

.card-footer {
  background-color: #f0f0f0;
  padding: 15px;
  border-top: 1px solid #ccc;
}
</style>

总结

组件插槽是Vue3中的一个重要特性,它允许你在组件中定义可替换的内容区域。通过默认插槽、具名插槽和作用域插槽,你可以实现各种复杂的布局和内容传递。

在使用插槽时,你应该合理选择插槽类型,保持插槽的清晰性,以及考虑插槽的性能。

在后续的章节中,我们将学习Vue3的组件生命周期,包括生命周期钩子的使用方法和最佳实践。

© 2026 编程马·菜鸟教程 版权所有