Vue 插槽(Slot)全解析:从 Vue2 到 Vue3 核心用法与案例

插槽 (Slot)是 Vue 中最强大的功能之一,它的核心作用是实现组件内容的分发,让子组件成为一个可定制、可复用的「容器」,父组件可以向子组件传递任意 HTML 结构、组件甚至逻辑,彻底解决了组件内容固化的问题。

一、插槽核心概念

简单理解:

  • 子组件:定义插槽位置(相当于预留一个「空位」)。
  • 父组件:向「空位」填充自定义内容(文本、HTML、组件都可以)。
  • 如果父组件不填充内容,子组件可以设置默认内容。

二、Vue3 插槽完整用法

Vue3 完全兼容 Vue2 插槽语法,废弃了旧版语法 ,统一使用更简洁的 v-slot 指令(简写 #),语法更直观、语义更清晰。

1. 默认插槽(匿名插槽)

适用场景:子组件只有一个需要分发的内容,无需指定名称。

子组件(Child.vue)

使用 <slot> 标签定义插槽,可设置默认内容:

javascript 复制代码
<template>
  <div class="child-box">
    <h3>子组件标题</h3>
    <!-- 默认插槽:父组件不传递内容时,显示默认值 -->
    <slot>我是插槽默认内容</slot>
  </div>
</template>

父组件使用

直接在子组件标签内写内容,会自动填充到默认插槽:

javascript 复制代码
<template>
  <Child>
    <!-- 填充到子组件默认插槽的内容 -->
    <p>我是父组件传递的自定义内容</p>
    <button>点击按钮</button>
  </Child>
</template>

<script setup>
// Vue3 组合式 API
import Child from './Child.vue'
</script>

2. 具名插槽

适用场景:子组件有多个需要分发的位置,通过名称区分插槽。

语法:

  • 子组件:<slot name="插槽名"></slot>
  • 父组件:#插槽名 或 v-slot:插槽名

子组件(Layout.vue)

javascript 复制代码
<template>
  <div class="layout">
    <!-- 头部插槽 -->
    <header>
      <slot name="header"></slot>
    </header>

    <!-- 中间默认插槽 -->
    <main>
      <slot></slot>
    </main>

    <!-- 底部插槽 -->
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

父组件使用

必须用 <template> 标签配合插槽名称指定内容位置:

javascript 复制代码
<template>
  <Layout>
    <!-- 填充 header 插槽:#header 是 v-slot:header 的简写 -->
    <template #header>
      <h1>页面标题</h1>
    </template>

    <!-- 填充默认插槽(可写 #default 或省略) -->
    <template #default>
      <p>页面主体内容</p>
    </template>

    <!-- 填充 footer 插槽 -->
    <template #footer>
      <span>版权信息 © 2025</span>
    </template>
  </Layout>
</template>

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

3. 作用域插槽

核心价值:子组件向父组件传递数据,父组件可以使用子组件的数据渲染自定义内容。

适用场景:列表组件、表格组件(子组件提供数据,父组件决定展示样式)。

子组件(List.vue)

通过 v-bind 把数据绑定到插槽上,暴露给父组件:

javascript 复制代码
<template>
  <div class="list">
    <slot 
      v-for="item in list" 
      :key="item.id"
      <!-- 子组件暴露数据:自定义名称="子组件数据" -->
      :item="item"
    >
    </slot>
  </div>
</template>

<script setup>
import { ref } from 'vue'
// 子组件内部数据
const list = ref([
  { id: 1, name: 'Vue3 教程' },
  { id: 2, name: '插槽实战' },
  { id: 3, name: '组合式 API' }
])
</script>

父组件使用

接收子组件传递的数据,语法:#插槽名="接收对象"

javascript 复制代码
<template>
  <List>
    <!-- 默认作用域插槽:scope 接收子组件传递的所有数据 -->
    <template #default="scope">
      <!-- 使用子组件的 item 数据 -->
      <div class="item">
        {{ scope.item.id }} - {{ scope.item.name }}
      </div>
    </template>
  </List>
</template>

解构写法(更简洁,推荐):

javascript 复制代码
<!-- 直接解构子组件传递的 item -->
<template #default="{ item }">
  <div class="item">{{ item.id }} - {{ item.name }}</div>
</template>
4. 动态插槽名

Vue3 支持动态绑定插槽名称,灵活性拉满:

javascript 复制代码
<template>
  <Layout>
    <!-- 动态插槽:slotName 是变量 -->
    <template #[slotName]>
      动态内容
    </template>
  </Layout>
</template>

<script setup>
import { ref } from 'vue'
const slotName = ref('header') // 可动态修改
</script>

三、Vue2 插槽用法(对比参考)

Vue2 分为旧语法和新语法(v-slot),Vue3 废弃了旧语法,只保留 v-slot 统一语法。

1. Vue2 默认插槽
javascript 复制代码
<!-- 子组件 -->
<slot>默认内容</slot>

<!-- 父组件 -->
<Child>
  父组件内容
</Child>
2. Vue2 具名插槽(旧语法 vs 新语法)

旧语法(废弃):slot="名称"

新语法(兼容):v-slot:名称(Vue 2.6+ 支持)

javascript 复制代码
<!-- 旧语法(不推荐,Vue3 已删除) -->
<template slot="header">
  头部内容
</template>

<!-- 新语法(和 Vue3 一致) -->
<template v-slot:header>
  头部内容
</template>
3. Vue2 作用域插槽(旧语法 vs 新语法)

旧语法(废弃):slot-scope

新语法(兼容):v-slot

javascript 复制代码
<!-- 旧语法 -->
<template slot="default" slot-scope="scope">
  {{ scope.item }}
</template>

<!-- 新语法(和 Vue3 一致) -->
<template v-slot:default="scope">
  {{ scope.item }}
</template>

四、Vue2 与 Vue3 插槽核心区别

特性 Vue2 Vue3
推荐语法 2.6+ 支持 v-slot,兼容旧语法 仅支持 v-slot(简写 #),废弃所有旧语法
旧语法 支持 slot、slot-scope 完全废弃,不再支持
作用域插槽 必须写在 <template> 上(新语法) 规则一致,更简洁
动态插槽 支持 支持,语法更简洁
写法限制 无特殊限制 具名插槽必须写在 <template> 上

一句话总结:Vue3 插槽是 Vue2 新语法的精简版,去掉了冗余语法,统一使用 #插槽名,学习成本更低,代码更简洁。

五、插槽使用注意事项

  1. 具名插槽必须配合 <template> :除了默认插槽,具名插槽 / 作用域插槽都要写在 <template> 标签内。
  2. 默认插槽简写 :#default 可以省略,直接写内容。
  3. 数据作用域:父组件插槽内容只能访问父组件数据,子组件插槽内容只能访问子组件数据(作用域插槽除外)。
  4. 默认内容优先级:父组件传递内容 → 覆盖子组件默认内容;不传递 → 显示默认内容。

六、实战场景:封装通用卡片组件

用 Vue3 插槽封装一个高复用卡片组件,演示默认 + 具名 + 作用域插槽组合使用:

子组件(Card.vue)

javascript 复制代码
<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" :time="currentTime"></slot>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const currentTime = ref(new Date().toLocaleString())
</script>

父组件使用

javascript 复制代码
<template>
  <Card>
    <!-- 头部 -->
    <template #header>
      <h4>自定义卡片标题</h4>
    </template>

    <!-- 内容 -->
    <p>这是卡片的自定义主体内容</p>

    <!-- 底部:接收子组件时间 -->
    <template #footer="{ time }">
      <span>更新时间:{{ time }}</span>
    </template>
  </Card>
</template>

总结

  • 插槽本质:组件内容分发工具,让子组件支持自定义内容。
  • Vue3 核心语法 :默认插槽、#名称(具名插槽)、#名称="数据"(作用域插槽)。
  • 与 Vue2 差异 :废弃 slot/slot-scope 旧语法,统一使用 v-slot 简写 #,更简洁规范。
  • 最佳实践:封装通用组件(列表、弹窗、布局、卡片)必用插槽,是 Vue 组件化开发的核心技能。

个人速记:

具名插槽 子组件用<scope name="xx">接收,父组件<template #xx>插入

作用域插槽 子组件用<scope name="xx" :变量名="item">,父组件<template #xxx="{ 变量名 }"> <span>更新时间:{``{ 变量名 }}</span> </template>接收子组件变量

相关推荐
沙漠之主17 小时前
C++编程教学设计资料:从入门到实战的完整课程方案
java·前端·c++
hasty17 小时前
不上传新包,也能改变用户拿到的版本:npm dist-tag 的 OIDC 权限治理
前端·npm·node.js
Csvn17 小时前
diff 算法(虚拟 DOM Reconciliation)
前端
前端snow18 小时前
ai agent --- 文件存储
前端
Frag0ut18 小时前
Chrome四大版本获取及共存指南:Stable/Beta/Dev/Canary
前端·chrome·浏览器·dev·beta·canary·共存版
IT_陈寒20 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端
广州华水科技20 小时前
单北斗GNSS变形监测在大坝安全监测中的应用与优势
前端
zeng不错20 小时前
B站 173 个投稿活动看到眼瞎?我写了个扩展,主打一个精准打击
前端
Latchh20 小时前
前端导出的JPEG红字发糊,质量要拉到100才清楚
前端·图像处理·人工智能·计算机视觉
默_笙21 小时前
🚦 请三个 AI 考官给 RAG 打分:量化评估实战(下)
前端·javascript