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. 避免过度使用,简单场景优先考虑普通插槽
相关推荐
我是伪码农1 小时前
Vue 1.23
前端·javascript·vue.js
wqwqweee1 小时前
Flutter for OpenHarmony 看书管理记录App实战:搜索功能实现
开发语言·javascript·python·flutter·harmonyos
HIT_Weston3 小时前
107、【Ubuntu】【Hugo】搭建私人博客:模糊搜索 Fuse.js(三)
linux·javascript·ubuntu
henujolly6 小时前
ethers.js读取合约信息
开发语言·javascript·区块链
毕设源码-郭学长6 小时前
【开题答辩全过程】以 基于Web的高校课程目标达成度系统设计与实现为例,包含答辩的问题和答案
前端
wuhen_n6 小时前
高阶函数与泛型函数的类型体操
前端·javascript·typescript
POLITE37 小时前
Leetcode 437. 路径总和 III (Day 16)JavaScript
javascript·算法·leetcode
難釋懷7 小时前
解决状态登录刷新问题
java·开发语言·javascript
ヤ鬧鬧o.8 小时前
多彩背景切换演示
前端·css·html·html5
一起养小猫8 小时前
Flutter实战:从零实现俄罗斯方块(三)交互控制与事件处理
javascript·flutter·交互