Vue插槽

下面,我们来系统的梳理关于 Vue 插槽 的基本知识点


一、插槽核心思想

插槽(Slot) 是 Vue 组件化的核心机制,用于实现 内容分发。它允许父组件向子组件传递 模板片段,使子组件具备更强的灵活性和复用性。插槽的核心价值在于:

  • 组件结构定制:父组件可自定义子组件的部分内容
  • UI 与逻辑解耦:子组件专注数据处理,父组件控制显示样式
  • 高阶组件模式:实现渲染委托、作用域隔离等高级特性

二、基础插槽类型

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

作用:接收父组件传递的 全部未命名内容

<!-- 子组件 ChildComponent.vue -->
<template>
  <div class="card">
    <slot>默认内容(父组件未传内容时显示)</slot>
  </div>
</template>

<!-- 父组件使用 -->
<ChildComponent>
  <p>这里的内容会替换 slot 标签</p> 
</ChildComponent>

特性

  • 一个组件只能有一个默认插槽
  • 支持设置默认内容(当父组件不传内容时显示)

2. 具名插槽(Named Slots)

作用:实现 多区块内容分发

<!-- 子组件 Layout.vue -->
<template>
  <div class="container">
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>  <!-- 默认插槽 -->
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<!-- 父组件使用 -->
<Layout>
  <template v-slot:header>
    <h1>页面标题</h1>
  </template>

  <p>主内容区域(默认插槽)</p>

  <template #footer>  <!-- 简写语法 -->
    <p>版权信息 © 2023</p>
  </template>
</Layout>

关键点

  • 使用 name 属性定义插槽名称(未命名即为默认插槽)
  • Vue2 使用 slot="name",Vue3 推荐 v-slot:name#name
  • 不同插槽可 独立控制内容

3. 作用域插槽(Scoped Slots)

作用:子组件向父组件 传递数据,实现 渲染委托

<!-- 子组件 DataList.vue -->
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <slot :item="item" :index="index"></slot>
    </li>
  </ul>
</template>

<!-- 父组件使用 -->
<DataList :items="userList">
  <template #default="{ item, index }">  <!-- Vue3 解构语法 -->
    <span>{{ index + 1 }}. {{ item.name }}(年龄:{{ item.age }})</span>
  </template>
</DataList>

核心机制

  • 子组件通过 <slot :data="data"> 暴露数据
  • 父组件通过 v-slot:name="slotProps" 接收数据
  • 支持 解构赋值重命名
    <template #header="{ title: newTitle }">
      {{ newTitle }}
    </template>
    

三、插槽特性详解

1. 编译作用域规则
  • 父级模板:所有内容在父级作用域中编译
  • 子级模板:所有内容在子级作用域中编译
<!-- 父组件 -->
<Child>
  <!-- 此处访问父组件数据 -->
  {{ parentData }}  
  <div :style="parentStyle"></div>
</Child>

<!-- 子组件 -->
<slot>
  <!-- 此处访问子组件数据 -->
  {{ childData }}  
</slot>
2. 动态插槽名
<template v-slot:[dynamicSlotName]>
  动态内容
</template>

<script>
export default {
  data() {
    return {
      dynamicSlotName: 'header'
    }
  }
}
</script>
3. 插槽复用与组合
<!-- 将多个插槽内容合并 -->
<template #default="slotProps">
  <slot name="prefix"></slot>
  {{ slotProps.data }}
  <slot name="suffix"></slot>
</template>

四、Vue2 与 Vue3 语法对比

特性Vue2 语法Vue3 语法
具名插槽<template slot="name"><template v-slot:name>#name
作用域插槽slot-scope="props"v-slot:name="props"
默认插槽作用域无法直接使用可用 #default="props"
插槽属性不支持支持 <slot :item="data">

五、最佳实践与性能优化

1. 设计原则
  • 单一职责:每个插槽应有明确的内容定位
  • 适度抽象:避免超过 3 层插槽嵌套
  • 命名规范:使用语义化名称(如 #header#item
2. 性能优化技巧
  • 对静态内容使用 v-once
    <template #header>
      <div v-once>固定标题</div>
    </template>
    
  • 避免在插槽内进行复杂计算(移至计算属性)
  • 作用域插槽传递 最小必要数据,避免传递大型对象
3. 常见错误
<!-- 错误:混用默认与具名插槽 -->
<Child>
  <div>默认内容</div>
  <template #footer>页脚</template>
  <div>其他内容</div> <!-- 此处内容会被丢弃 -->
</Child>

<!-- 正确:分离具名插槽 -->
<Child>
  <template #default>
    <div>默认内容</div>
    <div>其他内容</div>
  </template>
  <template #footer>页脚</template>
</Child>

六、实战案例

1. 可定制表格组件
<!-- TableComponent.vue -->
<template>
  <table>
    <thead>
      <tr>
        <th v-for="col in columns" :key="col.key">
          <slot :name="`header-${col.key}`" :column="col">
            {{ col.title }}  <!-- 默认显示列标题 -->
          </slot>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(row, index) in data" :key="row.id">
        <td v-for="col in columns" :key="col.key">
          <slot :name="`cell-${col.key}`" :row="row" :index="index">
            {{ row[col.key] }}  <!-- 默认显示单元格数据 -->
          </slot>
        </td>
      </tr>
    </tbody>
  </table>
</template>

使用示例

<TableComponent :columns="columns" :data="userData">
  <!-- 自定义邮箱列标题 -->
  <template #header-email>
    电子邮箱 <span class="required">*</span>
  </template>

  <!-- 自定义操作列单元格 -->
  <template #cell-actions="{ row }">
    <button @click="editUser(row)">编辑</button>
  </template>
</TableComponent>

2. 复合布局系统
<!-- LayoutSystem.vue -->
<template>
  <div class="layout">
    <div class="sidebar">
      <slot name="sidebar"></slot>
    </div>
    <div class="main">
      <div class="header">
        <slot name="header"></slot>
      </div>
      <div class="content">
        <slot></slot>
      </div>
    </div>
  </div>
</template>

<!-- 使用案例 -->
<LayoutSystem>
  <template #sidebar>
    <NavigationMenu />
  </template>
  
  <template #header>
    <SearchBar />
  </template>

  <ArticleContent />
</LayoutSystem>

七、总结表格

插槽类型语法核心能力典型场景
默认插槽<slot>基础内容分发通用容器组件
具名插槽<slot name="header">多区块内容控制布局系统、复杂卡片
作用域插槽<slot :data="row">子向父传递数据表格组件、列表渲染
动态插槽v-slot:[dynamicName]运行时决定插槽位置可配置化组件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

前端岳大宝

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

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

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

打赏作者

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

抵扣说明:

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

余额充值