Skip to content
第 8 章 前端 ⏱ 12 分钟阅读

第 8 章:插槽 ​

学习目标 ​

  • 区分默认插槽、具名插槽、作用域插槽
  • 用 useSlots / useAttrs 操作插槽
  • 实现可复用布局组件
  • 避开插槽封装的 3 个坑

一、默认插槽 ​

vue
<!-- Card.vue -->
<template>
  <div class="card">
    <slot>默认内容</slot>
  </div>
</template>
vue
<Card>
  <p>自定义内容</p>
</Card>

二、具名插槽 ​

vue
<!-- Layout.vue -->
<template>
  <div class="layout">
    <header><slot name="header" /></header>
    <main><slot /></main>           <!-- name 默认是 default -->
    <footer><slot name="footer" /></footer>
  </div>
</template>
vue
<Layout>
  <template #header>
    <h1>标题</h1>
  </template>
  <p>主体内容</p>
  <template #footer>
    <small>© 2026</small>
  </template>
</Layout>

⚠️ 坑 1:#header 是 v-slot:header 的简写,只能用在 <template> 或组件上。

三、作用域插槽(子提供数据) ​

vue
<!-- List.vue -->
<script setup lang="ts">
defineProps<{ items: { id: number; name: string }[] }>()
</script>

<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <slot :item="item" :index="item.id" />
    </li>
  </ul>
</template>
vue
<List :items="users">
  <template #default="{ item, index }">
    <strong>{{ index }}.</strong>
    <span>{{ item.name }}</span>
  </template>
</List>

四、解构默认值 ​

vue
<!-- 子组件 -->
<slot :user="user" :status="status">
  {{ user.name }} - {{ status }}     <!-- 父组件没传插槽时用这行 -->
</slot>

五、useSlots 编程访问 ​

vue
<script setup lang="ts">
import { useSlots } from 'vue'

const slots = useSlots()
console.log(slots.header ? '有 header' : '无 header')
</script>
vue
<template>
  <div v-if="slots.header" class="header">
    <slot name="header" />
  </div>
</template>

六、动态插槽名 ​

vue
<template>
  <Layout>
    <template #[dynamicName]>动态</template>
  </Layout>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const dynamicName = ref('footer')
</script>

七、实战:可复用表格 ​

vue
<!-- DataTable.vue -->
<script setup lang="ts" generic="T">
defineProps<{
  rows: T[]
  columns: { key: keyof T; title: string }[]
}>()
</script>

<template>
  <table>
    <thead>
      <tr>
        <th v-for="col in columns" :key="String(col.key)">{{ col.title }}</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(row, i) in rows" :key="i">
        <td v-for="col in columns" :key="String(col.key)">
          <slot :name="String(col.key)" :row="row" :index="i">
            {{ row[col.key] }}
          </slot>
        </td>
      </tr>
    </tbody>
  </table>
</template>

⚠️ 坑 2:通用组件 generic="T" 是 Vue 3.3+ 特性,版本低了会编译失败。 ⚠️ 坑 3:插槽里的响应式数据,父组件访问时不会响应,要用 v-for 重新计算。

八、本章小结 ​

类型用途
<slot>默认插槽
<slot name="x">具名插槽
<slot :data>作用域插槽
useSlots()在 setup 中访问 slots
generic="T"泛型组件

动手练习 ​

  1. 对话框:写 Modal.vue,用具名插槽 header / body / footer
  2. 作用域列表:写 UserList.vue,父组件自定义每行渲染方式
  3. 空状态:用 useSlots() 判断是否有 default 插槽,没有就显示"暂无数据"

下一章:第 9 章:路由 →

本站基于 VitePress 构建 · 由 StackHub 团队维护