【Vue】Vue基础----插槽(Slots)

Vue 中的插槽(Slots)是 Vue 组件化开发中一个非常强大的功能,它允许你定义可复用的模板,并在使用组件时向其中注入自定义内容。


1. 为什么需要插槽?

想象一个按钮组件:

<!-- Button.vue -->
<template>
  <button class="my-btn">
    <!-- 这里的内容应该由使用组件的人决定 -->
  </button>
</template>

如果没有插槽,你可能会用 props 来传递文本:

<Button text="Click me"></Button>

但这限制了只能传递文本,无法传递更复杂的 HTML 结构(如图标、样式等)。插槽就是为了解决这个问题而生的,它允许父组件向子组件传递任意模板内容。


2. 基本插槽 (Default Slot)

最基本的插槽,也称为默认插槽。

子组件中定义插槽 (Child.vue)

使用 <slot> 标签作为占位符。

<template>
  <div class="child-component">
    <h2>我是子组件的标题</h2>
    <!-- 插槽占位符 -->
    <slot></slot>
    <p>我是子组件的尾部</p>
  </div>
</template>
父组件中使用 (Parent.vue)

在组件标签内部写入的内容,会替换子组件中的 <slot></slot>

<template>
  <Child>
    <!-- 这部分内容会被注入到子组件的插槽中 -->
    <p>这是父组件传递过来的内容!</p>
    <button>一个按钮</button>
  </Child>
</template>

最终渲染结果:

<div class="child-component">
  <h2>我是子组件的标题</h2>
  <!-- 插槽被替换为 -->
  <p>这是父组件传递过来的内容!</p>
  <button>一个按钮</button>
  <p>我是子组件的尾部</p>
</div>

3. 后备内容 (Fallback Content)

你可以为插槽提供默认内容(后备内容)。如果父组件没有提供任何内容,后备内容就会显示。

子组件 (Child.vue)
<template>
  <button class="my-btn">
    <!-- 如果父组件没有提供内容,则显示“Submit” -->
    <slot>Submit</slot>
  </button>
</template>
父组件 (Parent.vue)
<!-- 使用后备内容 -->
<Child></Child> 
<!-- 渲染结果: <button class="my-btn">Submit</button> -->

<!-- 提供自定义内容 -->
<Child>Click Me!</Child>
<!-- 渲染结果: <button class="my-btn">Click Me!</button> -->

4. 具名插槽 (Named Slots)

当一个组件需要多个插槽时,就需要使用具名插槽来区分它们。

子组件 (Card.vue)

使用 name 属性给每个 <slot> 命名。不带 name<slot> 是默认插槽。

<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"></slot>
    </div>
  </div>
</template>
父组件 (Parent.vue)

使用 v-slot 指令(可简写为 #)在 <template> 上指定要插入哪个具名插槽。
Vue 2.6.0+ 语法 (推荐)

<template>
  <Card>
    <!-- 插入 header 插槽 -->
    <template v-slot:header>
      <h2>自定义标题</h2>
    </template>

    <!-- 插入默认插槽 (也可以不用 <template> 包裹) -->
    <p>这是卡片的主体内容...</p>

    <!-- 插入 footer 插槽 -->
    <template #footer> <!-- # 是 v-slot: 的简写 -->
      <button>保存</button>
    </template>
  </Card>
</template>

5. 作用域插槽 (Scoped Slots)

这是插槽最强大的功能。它允许子组件在插槽中向父组件传递数据,让父组件可以自定义如何渲染这些数据。

子组件 (TodoList.vue)

<slot> 上绑定属性(:todos="todos"),这些属性被称为插槽 Props

<template>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <!-- 将 todo 对象作为插槽 Prop 传递出去 -->
      <slot :todo="todo"></slot>
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      todos: [
        { id: 1, text: 'Learn Vue', isComplete: true },
        { id: 2, text: 'Build something awesome', isComplete: false }
      ]
    }
  }
}
</script>
父组件 (Parent.vue)

使用 v-slot 来接收子组件传递过来的数据。可以使用解构语法。

<template>
  <TodoList>
    <!-- 接收插槽 Props,命名为 slotProps -->
    <template v-slot:default="slotProps">
      <!-- 现在可以自由决定如何渲染每个 todo -->
      <span :style="{ textDecoration: slotProps.todo.isComplete ? 'line-through' : 'none' }">
        {{ slotProps.todo.text }}
      </span>
    </template>
  </TodoList>
</template>

使用解构语法更简洁:

<TodoList v-slot="{ todo }">
  <span :style="{ textDecoration: todo.isComplete ? 'line-through' : 'none' }">
    {{ todo.text }}
  </span>
</TodoList>

6. 具名作用域插槽 (Named Scoped Slots)

结合具名插槽和作用域插槽。

子组件 (DataTable.vue)
<template>
  <table>
    <thead>
      <tr>
        <th>Header</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="item in items" :key="item.id">
        <!-- 为每个具名插槽传递数据 -->
        <td><slot name="cell" :item="item"></slot></td>
      </tr>
    </tbody>
  </table>
</template>
父组件 (Parent.vue)
<template>
  <DataTable :items="userList">
    <template #cell="{ item }">
      <!-- 可以访问到子组件传来的 item -->
      {{ item.name }} - {{ item.email }}
    </template>
  </DataTable>
</template>

总结与对比

插槽类型关键字/用法目的
默认插槽<slot>接收未包裹在 <template> 中的内容。
具名插槽v-slot:name#name将内容分发到指定名称的插槽。
作用域插槽v-slot="data"子组件向父组件传递数据,父组件决定渲染样式。
后备内容<slot>默认内容</slot>父组件未提供内容时显示的默认值。

版本注意:

  • v-slot 指令在 Vue 2.6.0+ 中引入,取代了旧的 slotslot-scope 特性(现已废弃)。
  • 在 Vue 3 中,v-slot 是唯一推荐的用法。

简写规则:

  • v-slot:default 可以简写为 v-slot
  • v-slot:header 可以简写为 #header

插槽极大地提高了组件的灵活性和复用性,尤其是在构建通用组件(如模态框、卡片、列表、表格)时,它是不可或缺的工具。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝莓味的口香糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值