六维教程

Vue3 插槽基础

插槽要解决什么问题?先回想一下 Bootstrap 的卡片(card)。

Bootstrap 是个 CSS 框架,它的 card 实现原理很简单,就是给一个 div 套上样式类。

.card 负责边框、圆角、阴影这些外观,.card-body 只是一块留白的容器,除了这两层样式,Bootstrap 根本不碰里面的内容。

所以你爱放什么放什么,放一段文字、放一个列表、放一张图都行,<div class="card"> 和普通标签没区别,只是外观统一了。

现在想把这个思路搬进 Vue,做一个自己的 Card 组件,外壳固定,内部由每个页面决定。

但 Vue 组件是封装好的,不像 HTML 那样开个标签就能往里塞内容,外壳写好后,里面放什么就成了问题。

更关键的是,里面该放什么,只有用到它的页面(父组件)才知道

你写 Card 组件时,还没想好它会被用在哪几页,不可能把内容写进去。

内容得由每个页面自己提供,比如首页(父组件)给一段欢迎文字,博客列表(父组件)给文章标题和摘要。

所以内容必须由使用方传给 Card(子组件),Card 只负责把传进来的内容渲染到指定位置。

那怎么把内容传给子组件?如果不用插槽,只有两条路,都很别扭。

一是把内容写死在组件里:

<!-- Card.vue -->
<template>
  <div class="card">
    <div class="card-tip">这是一张卡片</div>
    <p>这里写死了一段文字</p>
  </div>
</template>

可是张三要放表单,李四要放另一个组件,只能复制两份几乎一样的 Card,改一处样式要改两处。

二是用 props 传 HTML 字符串:

<Card :html="'<p>这是一段文字</p>'" />

字符串是死的,变量、事件、组件全都绑不上,没法写复杂内容。

插槽(Slot)就是来解决这个矛盾的。

props 是”传数据”,插槽是”传内容 / 传结构”,父组件往子组件的固定位置塞入任意 HTML 或组件。

弹窗、卡片、导航栏、文章列表这类”外壳固定、内部可变”的组件,都靠插槽实现。

默认插槽

子组件里放一个 <slot> 当作”占位口”,父组件往里面放什么,它就在那渲染什么:

<!-- 子组件 Card.vue -->
<template>
  <div class="card">
    <div class="card-tip">这是一张卡片</div>
    <slot />                    <!-- 父组件内容塞到这里 -->
  </div>
</template>
<!-- 父组件 -->
<Card>
  <p>这是卡片里的自定义内容</p>
</Card>

不给插槽提供内容时,可以写默认内容兜底:

<slot>暂无内容</slot>

换句话说:子组件负责”提供位置和默认内容”,父组件负责”决定放什么”

具名插槽

一个组件往往有多个插槽位(头部、主体、底部),给 <slot>name 名字,父组件用 <template #名字> 精准投递:

<!-- 子组件 LayoutCard.vue -->
<template>
  <div class="layout-card">
    <header><slot name="header">默认标题</slot></header>
    <main><slot /></main>
    <footer><slot name="footer" /></footer>
  </div>
</template>
<!-- 父组件 -->
<LayoutCard>
  <template #header>我被放进 header</template>

  <!-- 没写 # 的内容默认进默认插槽(没 name 的那个) -->
  <p>我进 main</p>

  <template #footer>页脚</template>
</LayoutCard>
  • #名字<template v-slot:名字> 的简写,具名插槽必须用 <template> 包裹。
  • <template #header> 按名字对应;没名字的 <slot />默认插槽,父组件直接写内容就进默认插槽。

插槽 vs props 怎么选

对比 props 插槽
传什么 数据(字符串、数字、对象…) 内容(HTML、组件、结构)
谁决定结构 子组件里把数据摆成模板 父组件直接决定放什么
典型场景 配置项、数量、标题文字 卡片内容、弹窗体、导航项

只需要文字/数值用 props;需要完整 HTML/自定义组件就用插槽。两者不冲突,常混合使用。

速查卡片

场景 写法
预留默认插槽 子组件 <slot />
带默认内容 子组件 <slot>兜底文案</slot>
预留具名插槽 子组件 <slot name="header" />
投递具名插槽 父组件 <template #header>…</template>
上一篇
Vue3 组件 v-model
下一篇
Vue3 作用域插槽