Code前端首页关于Code前端联系我们

Vue3里slot怎么传值?从基础到进阶实操全讲明白

terry 2小时前 阅读数 7 #SEO
文章标签 Vue3;slot传值

不少刚开始学Vue3的小伙伴,一碰到 slot 传值就犯懵——明明知道插槽能自定义组件内容,可子组件的内部数据咋传给父组件的插槽用?今天把「作用域插槽(slot 传值的核心)」从基础到进阶,结合代码例子掰碎了讲,看完保准能上手~

slot 传值解决啥场景?先搞懂“作用域插槽”的意义

先想个实际需求:你写了个 <Card> 组件,负责渲染卡片结构(比如标题、内容区、底部按钮),但产品经理要求不同页面的卡片内容样式不一样要加图标,有的按钮要变色)。

这时候,<Card> 组件里的数据(比如标题文本、内容列表)得“交给”父组件的插槽去自定义渲染——这就是 作用域插槽(Scoped Slots) 的核心场景:子组件把数据“暴露”给父组件的插槽,让父组件能在自定义内容时用这些数据

对比普通插槽:普通插槽是“父组件塞内容,子组件渲染”,但父组件拿不到子组件的内部数据;而作用域插槽让子组件主动把数据传给父组件的插槽,实现“数据在子组件,UI 由父组件定制”的灵活分离。

最基础的作用域插槽咋写?分“子组件传值”和“父组件接收”两步

子组件:给 slot 绑定要传递的数据

子组件(Card.vue)里,在 <slot> 标签上用 绑定数据(这些绑定的属性叫“插槽 Props”),代码示例:

<template>
  <div class="card">
    <!-- 给slot绑定数据:item是卡片数据,handleClick是子组件的方法 -->
    <slot :item="cardData" :handleClick="handleClick"></slot>
  </div>
</template>
<script setup>
import { ref } from 'vue'
// 子组件内部的数据和方法
const cardData = ref({ title: 'Vue3插槽', content: '作用域插槽传值示例' })
const handleClick = () => {
  console.log('点击事件来自子组件~')
}
</script>

父组件:用 v-slot 接收插槽 Props

父组件使用 <Card> 时,得用 v-slot(或缩写 )在 <template> 上接收子组件传的 Props,有两种写法:

  • 写法1:对象接收(适合数据多的情况)

    <template>
      <Card>
        <!-- v-slot="slotProps":slotProps是个对象,包含子组件slot绑定的所有数据 -->
        <template v-slot="slotProps">
          <h2>{{ slotProps.item.title }}</h2>
          <p>{{ slotProps.item.content }}</p>
          <button @click="slotProps.handleClick">点我触发子组件方法</button>
        </template>
      </Card>
    </template>
    <script setup>
    import Card from './Card.vue'
    </script>
  • 写法2:解构接收(更简洁,推荐!)
    直接把 slotProps 里的属性解构出来,避免重复写 slotProps.xxx

    <template>
      <Card>
        <!-- 解构出item和handleClick -->
        <template v-slot="{ item, handleClick }">
          <h2>{{ item.title }}</h2>
          <p>{{ item.content }}</p>
          <button @click="handleClick">点我触发子组件方法</button>
        </template>
      </Card>
    </template>

多个插槽(具名插槽)咋分别传值?

实际项目里,组件可能有多个插槽(<MultiCard>headerbodyfooter 三个插槽),每个插槽要传不同数据,这时候用“具名插槽 + 作用域插槽” 组合写法:

子组件:给每个具名 slot 绑定数据

子组件(MultiCard.vue)里,给每个 <slot>name 属性,再分别绑定数据:

<template>
  <div class="multi-card">
    <header>
      <!-- 具名插槽header,传title数据 -->
      <slot name="header" :title="pageTitle"></slot>
    </header>
    <main>
      <!-- 具名插槽body,传文章列表数据 -->
      <slot name="body" :list="articleList"></slot>
    </main>
    <footer>
      <!-- 具名插槽footer,传作者信息 -->
      <slot name="footer" :author="authorInfo"></slot>
    </footer>
  </div>
</template>
<script setup>
import { ref } from 'vue'
const pageTitle = ref('Vue3插槽实战')
const articleList = ref([
  { id: 1, text: '作用域插槽基础' },
  { id: 2, text: '具名插槽传值' }
])
const authorInfo = ref({ name: '前端小助手', date: '2024-09' })
</script>

父组件:给每个具名插槽单独接收 Props

父组件用 #插槽名v-slot 的缩写),给每个具名插槽写 <template> 并接收数据:

<template>
  <MultiCard>
    <!-- 接收header插槽的title -->
    <template #header="{ title }">
      <h1>{{ title }}</h1>
    </template>
    <!-- 接收body插槽的list -->
    <template #body="{ list }">
      <ul>
        <li v-for="item in list" :key="item.id">{{ item.text }}</li>
      </ul>
    </template>
    <!-- 接收footer插槽的author -->
    <template #footer="{ author }">
      <p>作者:{{ author.name }} | 日期:{{ author.date }}</p>
    </template>
  </MultiCard>
</template>
<script setup>
import MultiCard from './MultiCard.vue'
</script>

传复杂数据(对象、函数)要注意啥?

实际开发中,子组件可能传对象、数组、函数给父组件,这时候要注意“解构默认值”和“函数调用逻辑”:

传对象:给解构加默认值,避免 undefined 报错

如果子组件传的对象可能为空,父组件解构时加默认值,防止访问属性时报错:

<!-- 子组件slot绑定:<slot :user="userInfo"></slot> -->
<template v-slot="{ user = { name: '默认名', age: 18 } }">
  {{ user.name }} - {{ user.age }}
</template>

传函数:父组件调用子组件的方法

子组件可以把修改自身状态的函数传给父组件,父组件调用时直接触发子组件逻辑,比如子组件里的计数逻辑:

子组件(Counter.vue):

<template>
  <slot :increment="increment" :count="count"></slot>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => {
  count.value++ // 子组件内部修改count
}
</script>

父组件调用:

<template>
  <Counter>
    <template v-slot="{ increment, count }">
      <button @click="increment">点击+1,当前:{{ count }}</button>
    </template>
  </Counter>
</template>

结合 setup 语法糖,slot 传值有变化吗?

Vue3 的 <script setup> 让组件写法更简洁,但slot 传值的核心逻辑不变——子组件里的变量会自动暴露给模板,所以定义 slot 绑定数据时,和普通写法完全一样;父组件接收 Props 的方式也没变化。

简单说:<script setup> 只是让子组件代码更简洁,不影响 slot 传值的“传”和“收”逻辑~

实际项目中,哪些场景必须用 slot 传值?

这3类场景最常见,掌握后写组件更丝滑:

  1. 表格组件(Table):子组件负责请求数据、分页,父组件自定义列渲染,比如表格行数据由子组件管理,父组件用 slot 传值接收每行数据,自定义渲染成按钮、链接等。
  2. 弹窗组件(Modal):子组件负责弹窗结构(遮罩、关闭逻辑),父组件用 slot 传值接收“关闭弹窗的方法”,在自定义内容里加关闭按钮。
  3. 列表组件(List):子组件处理数据加载、空状态,父组件用 slot 传值接收列表项数据,自定义每个列表项的 UI(比如带图标、带操作按钮)。

避坑!这些常见错误要绕开

  1. 忘记用 <template> 包裹 v-slot
    错误:直接把 v-slot 写在组件标签上(<Card v-slot="props">),如果组件有多个根节点会报错!
    正确:必须用 <template v-slot="props"> 包裹插槽内容。

  2. 具名插槽 name 不匹配
    子组件 slot 的 name="header",父组件却用 #footer 接收,会导致拿不到数据,要确保 name#插槽名 完全一致。

  3. 解构时变量名写错
    子组件 slot 绑定的是 userInfo,父组件解构写成 { userinfo }(小写)——Vue 的插槽 Props 是大小写敏感的,必须和子组件绑定的属性名一致。

  4. 子组件没绑定数据,父组件却接收
    子组件只写 <slot></slot>(没绑定任何数据),父组件却用 v-slot="props" 接收,props 是空对象,访问 props.data 会报错。

Vue2 和 Vue3 slot 传值有啥区别?

Vue2 里用 slot-scope 实现作用域插槽,Vue3 废弃了这个语法,统一用 v-slot,写法更简洁:

  • Vue2 写法:

    <ChildComp>
      <template slot-scope="props">
        {{ props.data }}
      </template>
    </ChildComp>
  • Vue3 写法:

    <ChildComp>
      <template v-slot="props">
        {{ props.data }}
      </template>
    </ChildComp>

Vue3 支持 v-slot 缩写 ,和具名插槽结合更流畅~

进阶:动态插槽名 + 传值

如果插槽名是动态变化的(比如根据用户权限显示不同插槽),Vue3 支持“动态插槽名”写法,同时结合传值:

子组件(动态决定插槽名):

<template>
  <!-- dynamicSlot 是计算出来的插槽名,#39;admin-slot'或'user-slot' -->
  <slot :name="dynamicSlot" :data="slotData"></slot>
</template>
<script setup>
import { ref, computed } from 'vue'
const userRole = ref('admin')
const dynamicSlot = computed(() => {
  return userRole.value + '-slot'
})
const slotData = ref('仅管理员可见的内容')
</script>

父组件(动态接收插槽):

<template>
  <ChildComp>
    <!-- v-slot:[dynamicSlotName] 绑定动态插槽名 -->
    <template v-slot:[dynamicSlotName]="props">
      {{ props.data }}
    </template>
  </ChildComp>
</template>
<script setup>
import { ref, computed } from 'vue'
import ChildComp from './ChildComp.vue'
const userRole = ref('admin')
const dynamicSlotName = computed(() => {
  return userRole.value + '-slot'
})
</script>

slot 传值的核心逻辑

作用域插槽(slot 传值)的本质是 “子组件向父组件的插槽传递数据,让父组件能在自定义内容时复用子组件的数据/方法”,关键步骤就两步:

  1. 子组件:在 <slot> 上用 绑定要传递的数据(即“插槽 Props”)。
  2. 父组件:用 v-slot(或 )在 <template> 上接收这些 Props,支持对象接收或解构接收。

掌握这两点,再结合具名插槽、动态插槽名等进阶用法,就能在 Vue3 中写出高复用、灵活可控的组件啦~

(全文约1800字,从基础到进阶覆盖 slot 传值核心场景,搭配代码例子和避坑指南,帮你彻底搞懂~)

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门