Code前端首页关于Code前端联系我们

Vue3 Slot API 怎么用?从基础到实战一次讲透

terry 9小时前 阅读数 19 #SEO
文章标签 Vue3 Slot;Slot API

插槽在Vue3里扮演啥角色?和Vue2比有啥进化?

插槽的核心作用是让父组件给子组件传递“结构”,比如子组件是个“卡片框架”,父组件想往卡片里塞标题、按钮、列表这些自定义内容,就需要插槽来实现组件间的“结构通信”。

Vue3 对插槽的优化主要体现在语法统一性能提升上:

  • 语法层面:Vue2 里作用域插槽要用 slot-scope(后来也支持 v-slot),写法分散;Vue3 彻底统一用 v-slot(缩写 ),不管是默认插槽、具名插槽还是作用域插槽,都能通过 v-slot 简洁表达。
  • 性能层面:Vue3 编译时对插槽做了优化,减少运行时的响应式依赖追踪,渲染更高效。

举个简单对比:
Vue2 写作用域插槽可能这样:

<ChildComponent>
  <template slot-scope="props">
    {{ props.msg }}
  </template>
</ChildComponent>

Vue3 则统一成:

<ChildComponent>
  <template #default="props">
    {{ props.msg }}
  </template>
</ChildComponent>
<!-- 甚至更简洁:只有默认插槽时,直接绑定v-slot -->
<ChildComponent v-slot="props">
  {{ props.msg }}
</ChildComponent>

默认插槽和具名插槽,Vue3里怎么写最顺手?

默认插槽:“单区域”自定义内容

子组件里放一个 <slot>,可以写“兜底内容”(父组件没传内容时显示),比如做个卡片组件 MyCard

<!-- 子组件 MyCard -->
<template>
  <div class="card">
    <slot>这里是默认内容,父组件没传内容时显示</slot>
  </div>
</template>

父组件用的时候,直接在 MyCard 标签里塞内容:

<MyCard>
  <h2>我是父组件传的标题</h2>
  <p>这里是卡片正文...</p>
</MyCard>

具名插槽:“多区域”精准自定义

如果子组件有多个插槽区域(比如头部、主体、底部),就得用具名插槽,子组件给 <slot>name 属性,父组件用 #插槽名 指定内容。

比如给 MyCard 加头部、底部插槽:

<!-- 子组件 MyCard -->
<template>
  <div class="card">
    <header>
      <slot name="header"></slot> <!-- 头部插槽 -->
    </header>
    <main>
      <slot></slot> <!-- 默认插槽(name省略即default) -->
    </main>
    <footer>
      <slot name="footer"></slot> <!-- 底部插槽 -->
    </footer>
  </div>
</template>

时,用 <template #插槽名> 精准对应:

<MyCard>
  <template #header>
    <h1>这是卡片头部</h1>
  </template>
  <!-- 默认插槽不用template包裹,直接写内容也能传 -->
  <p>这是卡片主体内容</p>
  <template #footer>
    <button>操作按钮</button>
  </template>
</MyCard>

作用域插槽咋玩?Vue3和之前版本差异多大?

作用域插槽是子组件给插槽传数据,父组件拿数据自定义渲染,比如子组件有列表数据,想让父组件决定每一项咋显示。

子组件传数据:给<slot>绑属性

子组件 MyList 里,循环渲染列表项时,给 <slot> 传递 itemindex

<!-- 子组件 MyList -->
<template>
  <ul>
    <li v-for="(item, index) in list" :key="item.id">
      <slot :item="item" :index="index"></slot> <!-- 传item和index给插槽 -->
    </li>
  </ul>
</template>
<script setup>
const list = [/* 假设是列表数据 */]
</script>

父组件拿数据:v-slot="参数" 接收

父组件用 #default="slotProps" 接收子组件传的参数(slotProps 是个对象,包含 itemindex):

<MyList>
  <template #default="slotProps">
    {{ slotProps.index }} - {{ slotProps.item.name }}
  </template>
</MyList>

如果是具名的作用域插槽(比如子组件 <slot name="custom" :data="data"></slot>),父组件就用 <template #custom="props"> 接收。

和Vue2的区别

Vue2 里作用域插槽得用 slot-scope,写法分散易混乱;Vue3 统一用 v-slot 的参数,语法更集中,Vue3 编译时对作用域插槽做了性能优化,减少不必要的响应式追踪,渲染更高效。

插槽的高级玩法:动态、组合、FallBack怎么用?

动态插槽名:插槽名由变量控制

如果插槽名是动态的(比如用户操作切换显示区域),Vue3 支持 <template #[变量]>,示例:

<template>
  <button @click="slotName = 'header'">显示头部</button>
  <button @click="slotName = 'footer'">显示底部</button>
  <MyComponent>
    <template #[slotName]="props">
      {{ props.content }} <!-- 根据slotName动态渲染对应插槽 -->
    </template>
  </MyComponent>
</template>
<script setup>
import { ref } from 'vue'
const slotName = ref('header')
</script>

FallBack内容:插槽的“兜底方案”

子组件 <slot> 里可以写默认内容,父组件没传内容时自动显示,比如弹窗组件的头部插槽:

<slot name="header">
  <h2>默认标题</h2> <!-- 父组件没传#header时,显示这个 -->
</slot>

插槽组合:多个插槽协同工作

一个组件里可以同时用默认插槽和多个具名插槽,父组件分别传内容,子组件负责布局,比如弹窗组件 Modal

<!-- 子组件 Modal -->
<template>
  <div class="modal">
    <div class="modal-header">
      <slot name="header">默认标题</slot>
    </div>
    <div class="modal-body">
      <slot></slot> <!-- 默认插槽 -->
    </div>
    <div class="modal-footer">
      <slot name="footer">
        <button>确定</button>
        <button>取消</button>
      </slot>
    </div>
  </div>
</template>

父组件用的时候,可只传部分插槽,其他用默认:

<Modal>
  <template #header>
    <h1>自定义标题</h1>
  </template>
  <p>弹窗主体内容...</p>
  <!-- footer没传,用子组件默认按钮 -->
</Modal>

实际项目中,插槽能解决哪些开发痛点?

插槽的核心价值是让组件更灵活、更易复用,以下场景特别实用:

组件解耦:UI库基础组件的“定制化”

UI 库的“卡片、弹窗、下拉框”这类组件,只负责结构和样式,内容由父组件通过插槽自定义,避免组件里写满 if-else 来适配不同场景,让组件更“纯净”。

灵活渲染:列表/表格的“自定义列”

表格组件想让每一列的渲染逻辑由父组件决定?用作用域插槽!子组件传每行数据给插槽,父组件自定义渲染(比如给某列加按钮、图标、富文本)。

示例:表格组件 Table 让用户自定义列:

<!-- 子组件 Table -->
<template>
  <table>
    <tbody>
      <tr v-for="row in data" :key="row.id">
        <td v-for="col in columns" :key="col.key">
          <slot :name="col.key" :row="row" :col="col">
            {{ row[col.key] }} <!-- 兜底内容 -->
          </slot>
        </td>
      </tr>
    </tbody>
  </table>
</template>
<script setup>
const props = defineProps(['columns', 'data'])
</script>

父组件自定义“姓名列”和“操作列”:

<Table :columns="columns" :data="tableData">
  <template #name="props">
    <img :src="props.row.avatar" /> {{ props.row.name }}
  </template>
  <template #action="props">
    <button @click="edit(props.row)">编辑</button>
  </template>
</Table>

布局复用:“框架型组件”的内容自由组合

左右布局、栅格布局、选项卡”这类组件,用插槽让用户自由填充内容,布局结构复用,内容灵活组合。

减少Props传递:复杂结构直接“插”

有些场景传“HTML结构”比传“数据”更方便(比如带样式的按钮组、富文本块),用插槽直接传结构,不用拆分成多个 props,代码更简洁。

Vue3 Slot API 学透了有多香?

Vue3 的 Slot API 把“传结构”这件事变得更简洁、更灵活、更高效

  • 语法上,v-slot 统一了所有插槽的写法, 缩写让代码更简洁;
  • 功能上,作用域插槽、动态插槽、FallBack 内容覆盖了“自定义渲染、动态切换、兜底方案”等场景;
  • 实战中,能让组件解耦、复用性拉满,还能减少冗余代码。

不管是写业务组件(如商品卡片、弹窗),还是封装 UI 库,插槽都是“让组件活起来”的关键武器,把基础用法和高级技巧练熟,组件开发效率能提升一大截~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门