Vue3 插槽的本质

Vue 插槽的本质:一个关于函数传递的故事

核心观点

向组件传递插槽,其本质就是向子组件传递一个特殊的对象。这个对象包含了多个函数,每个函数对应一个插槽,而函数的返回值就是该插槽要渲染的虚拟节点 (VNode)。

  • 具名插槽 :对象中以插槽名命名的属性,如 header
  • 默认插槽 :对象中名为 default 的属性。
  • 作用域插槽 :一个接收参数的函数,子组件调用它时传入的数据,就是父组件可以访问的 scope 数据。

因此,父组件定义插槽,是在"声明"这些函数;子组件使用插槽,是在"调用"这些函数。


1. 父组件:声明插槽函数 (模板语法如何编译)

我们在父组件中使用 <template> 语法来定义插槽,这是一种非常直观的"语法糖"。

父组件模板 (Parent.vue)

vue 复制代码
<template>
  <ChildComponent>
    <!-- 默认插槽 -->
    <p>这是默认插槽的内容</p>

    <!-- 具名插槽 "header" -->
    <template #header>
      <h1>我是 Header</h1>
    </template>

    <!-- 作用域插槽 "item" -->
    <template #item="scope">
      <div>
        来自子组件的数据: {{ scope.text }} (ID: {{ scope.id }})
      </div>
    </template>
  </ChildComponent>
</template>

在编译时,Vue 会将上述模板转换成类似下面这样的渲染函数调用,并生成你描述的那个 slots 对象:

编译后的概念

js 复制代码
// Vue 编译器将模板转换为类似下面的代码
import { createVNode } from 'vue'
import ChildComponent from './ChildComponent.js'

createVNode(ChildComponent, null, {
    // 这就是传递给子组件的 slots 对象
    default: () => [createVNode("p", null, "这是默认插槽的内容")],
    header: () => [createVNode("h1", null, "我是 Header")],
    item: (scope) => [ // 这是一个接收 scope 参数的函数
        createVNode("div", null, `来自子组件的数据: ${scope.text} (ID: ${scope.id})`)
    ]
})

2. 子组件:调用插槽函数

子组件通过 setup 函数的第二个参数 { slots } 接收到这个对象。然后,在需要渲染插槽的地方,直接调用这些函数即可。

子组件

js 复制代码
import { createElementVNode } from "vue"
export default {
    setup(_, { slots }) {
        // 正如你所说,使用插槽就是调用函数
        return () => {
           // 准备一些数据,用于传递给作用域插槽
           const scopeData = { text: "这是来自子组件的数据", id: 1 };
           // 调用 slots 对象上的函数来获取 VNode 数组作为子节点
           return createElementVNode("div", { class: "container" }, [
                // 1. 调用 header 函数,渲染具名插槽
                slots.header ? slots.header() : createElementVNode("p", null, "Header 的默认内容"),
                // 2. 调用 default 函数,渲染默认插槽
                slots.default ? slots.default() : createElementVNode("p", null, "Default 的默认内容"),
                // 3. 调用 item 函数并传入数据,渲染作用域插槽
                slots.item ? slots.item(scopeData) : null,
           ]);
        }
    }
}

总结

将插槽理解为"函数传递"是掌握其高级用法和渲染原理的关键。它解释了为什么作用域插槽能够从子组件获取数据,以及为什么我们可以用 JSX 或渲染函数灵活地创建和传递插槽。

相关推荐
奋斗吧程序媛12 小时前
补充一个小知识点:有关@click.native
前端·vue.js
英勇无比的消炎药13 小时前
一行命令背后:TinyRobot CLI 如何重构 AI 对话接入的效率范式
vue.js·aigc
jay神15 小时前
基于 FastAPI + Vue 的宠物领养管理系统
前端·vue.js·python·毕业设计·fastapi·宠物
一杯奶茶¥15 小时前
水果销售网站 CRM客户信息管理系统 超市管理系 酒店管理系统 健身房管理系统 在线音乐网站 校园招聘系统
java·vue.js·spring boot·mysql·spring·java项目
英勇无比的消炎药15 小时前
一站式搞定品牌风格:TinyRobot 主题定制从入门到精通
vue.js
尽欢i17 小时前
Vue3 customRef 封神教程:防抖、本地存储、自动埋点一套搞定,模板干干净净
前端·javascript·vue.js
因_崔斯汀17 小时前
Vue 模板编译:HTML 是怎么变成 JS 的?
前端·vue.js
英勇无比的消炎药18 小时前
样式随心定制:TinyRobot 样式覆写与 CSS 变量实战解析
vue.js
疯狂的魔鬼18 小时前
多角色督办任务详情页:从权限矩阵到组件拆分的完整实现
前端·vue.js·架构
英勇无比的消炎药18 小时前
拆解内核:深入分析 TinyRobot 输入区组件设计与实现原理
vue.js