Vue 作用域插槽

Vue 作用域插槽(Scoped Slots)学习笔记

一、核心概念

作用域插槽是 Vue 插槽的高级用法,核心解决了子组件数据向父组件插槽反向传递的问题:

  • 普通插槽:仅支持父组件向子组件传递结构,无法访问子组件内部数据
  • 作用域插槽:子组件通过"插槽 Prop"暴露内部数据,父组件接收后可自定义渲染逻辑,实现"逻辑复用+样式自定义"的灵活组合

本质上是子组件向父组件插槽传参,使插槽内容能与子组件数据联动。

二、核心差异:普通插槽 vs 作用域插槽

特性 普通插槽 作用域插槽
数据流向 父组件→子组件 子组件→父组件(插槽内)
父组件访问子组件数据 不可 可(通过插槽 Prop 接收)
典型场景 固定结构传递 动态结构渲染

三、基础实现步骤

1. 子组件:定义插槽并暴露数据

使用v-bind:属性名="数据"(简写:属性名="数据")为插槽绑定"插槽 Prop":

vue 复制代码
<!-- 子组件 List.vue -->
<template>
  <div class="list-container">
    <div v-for="(item, index) in list" :key="item.id">
      <!-- 暴露列表项、索引和激活状态 -->
      <slot :item="item" :index="index" :isActive="index === currentIndex"></slot>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const list = ref([
  { id: 1, name: 'Vue', desc: '前端框架' },
  { id: 2, name: 'React', desc: 'UI库' },
  { id: 3, name: 'Angular', desc: '全栈框架' }
])

const currentIndex = ref(0)
</script>

2. 父组件:接收插槽 Prop 并渲染

使用v-slot:插槽名="接收变量"(简写#插槽名="接收变量")接收数据:

vue 复制代码
<!-- 父组件 Parent.vue -->
<template>
  <div>
    <h3>框架列表</h3>
    <List>
      <!-- 完整写法 -->
      <template v-slot:default="slotProps">
        <div class="list-item" :class="{ active: slotProps.isActive }">
          <span>{{ slotProps.index + 1 }}. {{ slotProps.item.name }}</span>
          <p>{{ slotProps.item.desc }}</p>
        </div>
      </template>
    </List>
  </div>
</template>

3. 简化写法:解构插槽 Prop

vue 复制代码
<List>
  <!-- 解构写法 -->
  <template #default="{ item, index, isActive }">
    <div class="list-item" :class="{ active: isActive }">
      <span>{{ index + 1 }}. {{ item.name }}</span>
      <p>{{ item.desc }}</p>
    </div>
  </template>
</List>

四、进阶用法:具名作用域插槽

1. 子组件定义多个插槽

vue 复制代码
<!-- 子组件 Card.vue -->
<template>
  <div class="card">
    <slot name="title" :title="cardTitle"></slot>
    <slot name="content" :content="cardContent" :author="author"></slot>
    <slot name="footer" :isLike="isLike" @toggleLike="toggleLike"></slot>
  </div>
</template>

2. 父组件针对性接收数据

vue 复制代码
<Card>
  <template #title="{ title }">
    <h2 class="card-title">{{ title }}</h2>
  </template>
  
  <template #content="{ content, author }">
    <p class="card-content">{{ content }}</p>
    <p class="card-author">作者:{{ author }}</p>
  </template>
  
  <template #footer="{ isLike, toggleLike }">
    <button @click="toggleLike">
      {{ isLike ? '已点赞' : '点赞' }}
    </button>
  </template>
</Card>

五、实用技巧

1. 默认插槽简写

vue 复制代码
<!-- 简写前 -->
<List>
  <template #default="{ item }">{{ item.name }}</template>
</List>

<!-- 简写后 -->
<List #="{ item }">
  <span>{{ item.name }}</span>
</List>

2. 插槽 Prop 重命名

vue 复制代码
<List #="{ item: frameworkItem }">
  <span>{{ frameworkItem.name }}</span>
</List>

3. 设置默认值

vue 复制代码
<List #="{ item = { name: '默认框架', desc: '无描述' } }">
  <span>{{ item.name }}</span>
  <p>{{ item.desc }}</p>
</List>

六、典型应用场景

  1. 列表组件:子组件处理数据获取和分页,父组件自定义项样式
  2. 表格组件:子组件管理表格结构,父组件定制单元格内容
  3. 容器组件:子组件提供基础结构和状态,父组件定义内容
  4. 通用组件:适应多种场景的可复用组件

七、注意事项

  1. 插槽 Prop 仅在该插槽模板内有效
  2. 避免过度使用,简单场景优先考虑普通插槽
相关推荐
东方小月2 小时前
从零开发一个 Coding Agent(四):使用状态机校验大模型事件流
前端·人工智能·后端
想做后端的前端2 小时前
WebGL实现FPS游戏
vue.js·游戏·webgl
Csvn2 小时前
🧩 ESM vs CJS 混用的 7 个「天坑」——从 TypeScript 编译到 Node 与浏览器
前端
Csvn2 小时前
🎯 Web 性能 API 集合:Performance Observer 的 5 个冷门妙用
前端
Csvn2 小时前
深入 React 闭包陷阱:从根源上理解并根治 stale closure
前端
whyfail3 小时前
前端学 Spring Boot(8):接口为什么越用越慢?
前端·spring boot·后端
用户059540174463 小时前
LangChain 记忆测试踩坑实录:这两个坑让我排查了 4 小时
前端·css
程序员黑豆3 小时前
鸿蒙应用开发:@Monitor 装饰器使用教程
前端·harmonyos
用户938515635073 小时前
从零构建《天龙八部》知识库:EPUB 加载→文本分割→向量嵌入→Milvus 存储→RAG 问答,一条链路打通
javascript·人工智能·全栈
SamChan904 小时前
在Web应用中集成PDF多语言翻译功能:PDFTranslator API实战指南
前端·python·ai·pdf·yapi·机器翻译