Vue 插槽(Slots)全面解析与实战指南

一、为什么需要插槽?

在开发组件时,props 只能传递数据 ,但很多场景下我们需要传递 模板内容

比如一个按钮组件,我们希望它有统一的样式,但内部文字或图标由外部决定。这时就用到 插槽(slot)

你可以把插槽理解为:

👉 组件的"占位符" ,由父组件决定填充的内容。


二、插槽的基础用法

1. 默认插槽

📌 父组件使用:

js 复制代码
<!-- 父组件 -->
<FancyButton>
  点我一下! <!-- 插槽内容 -->
</FancyButton>

📌 子组件 FancyButton.vue:

js 复制代码
<template>
  <button class="fancy-btn">
    <!-- 插槽出口,父组件传什么,这里就显示什么 -->
    <slot></slot>
  </button>
</template>

📌 渲染结果:

ini 复制代码
<button class="fancy-btn">点我一下!</button>

✅ 这样 FancyButton 的样式固定,但内容灵活。


2. 默认内容

如果父组件没有传递内容,可以给插槽设置 默认值

js 复制代码
<!-- 子组件 SubmitButton.vue -->
<template>
  <button type="submit">
    <slot>提交</slot> <!-- 默认是"提交" -->
  </button>
</template>

父组件:

js 复制代码
<SubmitButton />   <!-- 没传内容 -->
<SubmitButton>保存</SubmitButton> <!-- 传了内容 -->

结果:

js 复制代码
<button type="submit">提交</button>
<button type="submit">保存</button>

3. 具名插槽

有时组件内部有多个位置需要插入不同的内容,比如一个布局组件:

js 复制代码
<!-- BaseLayout.vue -->
<template>
  <div class="container">
    <header><slot name="header"></slot></header>
    <main><slot></slot></main> <!-- 默认插槽 -->
    <footer><slot name="footer"></slot></footer>
  </div>
</template>

父组件使用:

js 复制代码
<BaseLayout>
  <template #header>
    <h1>我是标题</h1>
  </template>

  <p>正文内容...</p> <!-- 默认插槽 -->

  <template #footer>
    <p>我是底部信息</p>
  </template>
</BaseLayout>

📌 渲染结果:

js 复制代码
+--------------------+
| 我是标题           |
+--------------------+
| 正文内容...        |
+--------------------+
| 我是底部信息       |
+--------------------+

可以把具名插槽想象成给"占位符"贴上了标签,方便对应。


4. 条件插槽

如果某个插槽内容没有传递,可以通过 $slots 判断是否需要渲染:

js 复制代码
<Card>
  <template #header>头部</template>
</Card>
js 复制代码
<!-- Card.vue -->
<template>
  <div class="card">
    <div v-if="$slots.header"><slot name="header" /></div>
    <div v-if="$slots.default"><slot /></div>
    <div v-if="$slots.footer"><slot name="footer" /></div>
  </div>
</template>

5. 动态插槽名

插槽的名字也可以动态传入:

js 复制代码
<base-layout>
  <template v-slot:[dynamicSlot]>
    动态内容
  </template>
</base-layout>

三、作用域插槽(Scoped Slots)

默认情况下,插槽内容只能访问父组件的数据

但有时我们希望子组件把一些数据"传出来",让父组件在插槽里使用。

📌 子组件:

js 复制代码
<!-- MyComponent.vue -->
<template>
  <slot :text="greeting" :count="1"></slot>
</template>

<script setup>
const greeting = "你好";
</script>

📌 父组件:

js 复制代码
<MyComponent v-slot="{ text, count }">
  {{ text }} - 次数:{{ count }}
</MyComponent>

结果:

复制代码
你好 - 次数:1

📌 类比 JavaScript:

js 复制代码
function MyComponent(slotFn) {
  const data = { text: "你好", count: 1 }
  return slotFn(data) // 调用函数并传入参数
}

✅ 所以作用域插槽可以理解为:子组件给父组件"回调函数"传参


具名作用域插槽

js 复制代码
<MyComponent>
  <template #header="{ message }">
    <h2>{{ message }}</h2>
  </template>
</MyComponent>

子组件:

js 复制代码
<slot name="header" :message="'来自子组件的数据'"></slot>

四、实战案例

1. 高级列表组件

js 复制代码
<!-- FancyList.vue -->
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <!-- 把 item 数据传给插槽 -->
      <slot name="item" v-bind="item"></slot>
    </li>
  </ul>
</template>

<script setup>
import { ref } from "vue";
const items = ref([
  { id: 1, text: "Vue", likes: 100 },
  { id: 2, text: "React", likes: 200 },
]);
</script>

父组件:

js 复制代码
<FancyList>
  <template #item="{ text, likes }">
    <p>{{ text }} ❤️ {{ likes }}</p>
  </template>
</FancyList>

结果:

复制代码
Vue ❤️ 100
React ❤️ 200

2. 无渲染组件

封装逻辑但不渲染视图,内容交给父组件:

js 复制代码
<!-- MouseTracker.vue -->
<template>
  <slot :x="x" :y="y"></slot>
</template>

<script setup>
import { ref, onMounted } from "vue";
const x = ref(0), y = ref(0);
onMounted(() => {
  window.addEventListener("mousemove", e => {
    x.value = e.pageX;
    y.value = e.pageY;
  });
});
</script>

父组件:

js 复制代码
<MouseTracker v-slot="{ x, y }">
  鼠标位置:{{ x }} , {{ y }}
</MouseTracker>

五、知识点图解

lua 复制代码
父组件 ----> 子组件
   │           │
   │ props     │
   │ slot内容  │ <slot> 占位符
   ▼           ▼
插槽渲染 = 父组件内容 + 子组件外壳

六、总结

  1. 默认插槽:没有名字的插槽,占位填充内容。

  2. 默认内容:父组件没传时,slot 会显示默认值。

  3. 具名插槽:给 slot 命名,实现多出口填充。

  4. 条件插槽:通过 $slots 判断是否存在内容。

  5. 动态插槽名:slot 的名字可动态绑定。

  6. 作用域插槽:子组件把数据传给插槽,让父组件使用。

  7. 实战场景:列表组件、无渲染组件,逻辑和视图分离。

👉 插槽的核心价值:

让组件更灵活、可复用,同时保留样式与逻辑的封装性。

相关推荐
魔术师卡颂3 分钟前
不就写提示词?提示词工程为啥是工程?
前端·人工智能·后端
訾博ZiBo36 分钟前
【Vibe Coding】001-前端界面常用布局
前端
IT_陈寒39 分钟前
《Redis性能翻倍的7个冷门技巧,90%开发者都不知道!》
前端·人工智能·后端
歪歪1001 小时前
React Native开发Android&IOS流程完整指南
android·开发语言·前端·react native·ios·前端框架
知识分享小能手1 小时前
uni-app 入门学习教程,从入门到精通,uni-app组件 —— 知识点详解与实战案例(4)
前端·javascript·学习·微信小程序·小程序·前端框架·uni-app
ZYMFZ1 小时前
python面向对象
前端·数据库·python
长空任鸟飞_阿康1 小时前
在 Vue 3.5 中优雅地集成 wangEditor,并定制“AI 工具”下拉菜单(总结/润色/翻译)
前端·vue.js·人工智能
lapiii3581 小时前
快速学完React计划(第一天)
前端·react.js·前端框架
苏打水com1 小时前
从 HTML/CSS/JS 到 React:前端进阶的平滑过渡指南
前端·javascript·html