插槽(Slots):让组件更灵活

插槽(Slots):让组件更灵活

插槽让你在组件中预留一个"口子",让父组件决定里面放什么。这是 Vue 最强大的组合特性之一。

默认插槽

子组件定义插槽:

<!-- Card.vue -->
<template>
  <div class="card">
    <h3>{{ title }}</h3>
    <slot></slot>
  </div>
</template>

<script setup lang="ts">
defineProps<{ title: string }>()
</script>

父组件填充:

<Card title="用户信息">
  <p>这里是插槽内容</p>
  <p>可以放任意内容</p>
</Card>

具名插槽

子组件有多个插槽,给它们起名字:

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

父组件指定插槽:

<Modal>
  <template #header>
    <h2>标题</h2>
  </template>

  <p>主要内容</p>

  <template #footer>
    <button>取消</button>
    <button>确定</button>
  </template>
</Modal>

#headerv-slot:header 的简写。

作用域插槽

子组件的数据可以传递给插槽,让父组件决定怎么渲染:

<!-- UserList.vue -->
<script setup lang="ts">
const users = ref([
  { name: '张三', age: 25 },
  { name: '李四', age: 30 }
])
</script>

<template>
  <div>
    <slot v-for="user in users" :user="user"></slot>
  </div>
</template>

父组件决定渲染方式:

<UserList>
  <template #default="{ user }">
    <p>{{ user.name }} - {{ user.age }}岁</p>
  </template>
</UserList>

动态插槽名

插槽名也可以是动态的:

<template #[slotName]>内容</template>

<script setup>
const slotName = ref('header')
</script>

插槽的典型场景

布局组件

<!-- Layout.vue -->
<template>
  <div class="layout">
    <aside><slot name="sidebar" /></aside>
    <main><slot /></main>
  </div>
</template>

表单组件

<!-- Form.vue -->
<template>
  <form>
    <slot name="fields" :formData="formData" />
    <button @click.prevent="handleSubmit">提交</button>
  </form>
</template>

总结

  • <slot> 定义插槽位置
  • name 属性定义具名插槽
  • #slotName 使用具名插槽
  • 作用域插槽让子组件数据传给父组件
  • 插槽让组件更通用、更灵活

下篇讲自定义指令和 Teleport。

最后更新 4/30/2026, 8:57:45 AM