当前位置: 首页 > article >正文

Vue3 插槽(Slots)用法总结

1. 默认插槽(Default Slots)

默认插槽是最基本的插槽类型,用于在组件中插入内容。

1.1 基本用法

<!-- BaseCard.vue -->
<template>
  <div class="card">
    <slot></slot>  <!-- 默认插槽 -->
  </div>
</template>

<!-- 使用组件 -->
<template>
  <BaseCard>
    <p>这是插入到默认插槽的内容</p>
  </BaseCard>
</template>

1.2 带默认内容的插槽

<!-- BaseButton.vue -->
<template>
  <button class="btn">
    <slot>
      点击按钮  <!-- 当没有提供内容时显示的默认内容 -->
    </slot>
  </button>
</template>

<!-- 使用组件 -->
<template>
  <BaseButton>提交</BaseButton>  <!-- 显示"提交" -->
  <BaseButton />  <!-- 显示"点击按钮" -->
</template>

2. 具名插槽(Named Slots)

具名插槽允许我们在组件中定义多个插槽,并通过名字来区分。

2.1 基本用法

<!-- LayoutComponent.vue -->
<template>
  <div class="layout">
    <header>
      <slot name="header"></slot>
    </header>
    
    <main>
      <slot></slot>  <!-- 默认插槽 -->
    </main>
    
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<!-- 使用组件 -->
<template>
  <LayoutComponent>
    <template #header>
      <h1>网站标题</h1>
    </template>

    <template #default>
      <p>主要内容区域</p>
    </template>

    <template #footer>
      <p>版权信息 © 2024</p>
    </template>
  </LayoutComponent>
</template>

2.2 动态插槽名

<!-- DynamicSlot.vue -->
<template>
  <div class="container">
    <slot :name="dynamicSlotName"></slot>
  </div>
</template>

<script setup>
const dynamicSlotName = ref('content')
</script>

<!-- 使用组件 -->
<template>
  <DynamicSlot>
    <template #[dynamicSlotName]>
      <p>动态插槽内容</p>
    </template>
  </DynamicSlot>
</template>

3. 作用域插槽(Scoped Slots)

作用域插槽允许子组件向插槽内容传递数据。

3.1 基本用法

<!-- ItemList.vue -->
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <slot :item="item" :index="index">
        <!-- 提供默认内容 -->
        {{ item.name }}
      </slot>
    </li>
  </ul>
</template>

<script setup>
const items = ref([
  { id: 1, name: '项目1', description: '描述1' },
  { id: 2, name: '项目2', description: '描述2' }
])
</script>

<!-- 使用组件 -->
<template>
  <ItemList>
    <template #default="{ item, index }">
      <div class="item">
        <h3>{{ index + 1 }}. {{ item.name }}</h3>
        <p>{{ item.description }}</p>
      </div>
    </template>
  </ItemList>
</template>

3.2 多个作用域插槽

<!-- DataTable.vue -->
<template>
  <table>
    <thead>
      <tr>
        <th v-for="column in columns" :key="column.key">
          <slot name="header" :column="column">
            {{ column.title }}
          </slot>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="row in data" :key="row.id">
        <td v-for="column in columns" :key="column.key">
          <slot :name="column.key" :row="row" :value="row[column.key]">
            {{ row[column.key] }}
          </slot>
        </td>
      </tr>
    </tbody>
  </table>
</template>

<!-- 使用组件 -->
<template>
  <DataTable :columns="columns" :data="tableData">
    <!-- 自定义表头 -->
    <template #header="{ column }">
      <strong>{{ column.title.toUpperCase() }}</strong>
    </template>

    <!-- 自定义状态列 -->
    <template #status="{ value }">
      <span :class="value">{{ value }}</span>
    </template>

    <!-- 自定义操作列 -->
    <template #actions="{ row }">
      <button @click="editRow(row)">编辑</button>
      <button @click="deleteRow(row)">删除</button>
    </template>
  </DataTable>
</template>

4. 实际应用示例

4.1 可复用的模态框组件

<!-- Modal.vue -->
<template>
  <div v-if="modelValue" class="modal">
    <div class="modal-content">
      <div class="modal-header">
        <slot name="header">
          <h3>默认标题</h3>
        </slot>
        <button @click="$emit('update:modelValue', false)">×</button>
      </div>

      <div class="modal-body">
        <slot></slot>
      </div>

      <div class="modal-footer">
        <slot name="footer" :close="close">
          <button @click="close">关闭</button>
        </slot>
      </div>
    </div>
  </div>
</template>

<script setup>
const props = defineProps({
  modelValue: Boolean
})

const emit = defineEmits(['update:modelValue'])

const close = () => {
  emit('update:modelValue', false)
}
</script>

<!-- 使用模态框 -->
<template>
  <Modal v-model="showModal">
    <template #header>
      <h3>确认删除</h3>
    </template>

    <p>确定要删除这条记录吗?</p>

    <template #footer="{ close }">
      <button @click="handleDelete">确认</button>
      <button @click="close">取消</button>
    </template>
  </Modal>
</template>

4.2 高级列表组件

<!-- ListView.vue -->
<template>
  <div class="list-view">
    <div class="list-header">
      <slot name="header" :total="items.length">
        <h2>列表 ({{ items.length }})</h2>
      </slot>
    </div>

    <div class="list-filters">
      <slot name="filters" :filters="filters" :updateFilter="updateFilter">
        <!-- 默认过滤器UI -->
      </slot>
    </div>

    <div class="list-content">
      <template v-if="filteredItems.length">
        <div v-for="item in filteredItems" :key="item.id" class="list-item">
          <slot name="item" :item="item">
            {{ item.name }}
          </slot>
        </div>
      </template>
      <template v-else>
        <slot name="empty">
          <p>暂无数据</p>
        </slot>
      </template>
    </div>

    <div class="list-footer">
      <slot name="footer" :total="filteredItems.length"></slot>
    </div>
  </div>
</template>

5. 最佳实践

  1. 插槽命名规范

    • 使用语义化的名称
    • 保持命名一致性
    • 使用小写字母和连字符
  2. 默认内容

    • 为插槽提供合理的默认内容
    • 确保组件在没有提供插槽内容时也能正常工作
  3. 作用域插槽数据

    • 只传递必要的数据
    • 使用清晰的属性名
    • 考虑数据的响应性
  4. 性能考虑

    • 避免在插槽中传递大量数据
    • 合理使用缓存机制

http://www.kler.cn/a/517428.html

相关文章:

  • 物业管理平台系统提升社区智能化服务效率与管理水平
  • (5)STM32 USB设备开发-USB键盘
  • Spring Boot 3.4 正式发布,结构化日志!
  • 激活版,快速安装
  • 【Nacos】负载均衡
  • lightgbm做分类
  • 一组开源、免费、Metro风格的 WPF UI 控件库
  • DBeaver下载安装及数据库连接(MySQL)
  • 初步理解数据结构
  • 每日一题 419. 棋盘上的战舰
  • GESP2024年6月认证C++六级( 第三部分编程题(2)二叉树)
  • react native i18n插值:跨组件trans
  • 麒麟操作系统基础知识保姆级教程(二十一)进入单用户模式
  • UE5 特效
  • 面试-二维数组
  • Oracle 创建用户和表空间
  • 第15章 监控任务的生命周期(Java高并发编程详解:多线程与系统设计)
  • Servlet 详解
  • EMC常用器件选型(一)
  • 提示词的艺术 ---- AI Prompt 进阶(提示词框架)
  • 三、双链表
  • 算法基础 -- Trie压缩树原理
  • 浏览器hid 和蓝牙bluetooth技术区别
  • WPF 打印功能实现
  • LPDDR4 precharge和selfresh 详解
  • .NET9增强OpenAPI规范,不再内置swagger