作用域插槽的本质是函数式渲染委托,即子组件提供数据、父组件决定渲染,vue通过编译将v-slot转为接收props的函数,子组件调用时传入响应式数据,实现单向数据透出与动态vnode生成。

作用域插槽的核心在于“数据由子提供、渲染由父决定”,它不是简单的 HTML 内容搬运,而是 Vue 在编译和运行时协同完成的一次函数式委托渲染。理解这点,就抓住了底层逻辑的关键。
作用域插槽的本质是渲染函数的参数传递
Vue 在模板编译阶段,会把带参数的 <template v-slot:default="props"></template> 转换成一个接收 props 的函数,并作为 scopedSlots 选项传给子组件。子组件内部调用这个函数时,把自身数据作为实参传入——本质上就是一次函数调用。
- 父组件写法:
<child><template user>{{ user.name }}</template></child> - 编译后等价于:
scopedSlots: { default: (props) => h('span', props.user.name) } - 子组件中执行:
slots.default({ user: { name: 'Alice' } }),触发父定义的渲染逻辑
数据流动方向:子 → 父 → 子(最终渲染)
注意这不是双向绑定,也不是事件通信,而是一次单向的数据透出 + 渲染委托。子组件主动把数据“暴露”给插槽,父组件拿到后生成 VNode,再交还给子组件挂载。整个过程保持响应性:若 user.name 是响应式数据,父模板中的 {{ user.name }} 仍能自动更新。
- 子组件通过
<slot :user="currentUser"></slot>绑定数据(v-bind 编译为 slotProps 对象属性) - 父组件用解构语法
#default="{ user }"接收,本质是解构传入的 slotProps 对象 - 只要
currentUser是 reactive 或 ref,其变化就会触发父侧插槽内容的重新求值
Vue 3 中的 Composition API 配合方式
在 setup() 中使用作用域插槽更直观:子组件直接 return 数据,父组件在模板里消费,无需操作渲染函数。但底层仍是同一套机制——slots 对象本身是响应式的函数集合。
- 子组件 setup 中可返回:
const items = ref([{ id: 1, label: 'Home' }]); return { items }; - 模板中:
<slot name="item" :items="items"></slot> - 父组件用
<template items><li v-for="i in items" :key="i.id">{{ i.label }}</li></template>
常见误区与关键细节
作用域插槽容易被当成“子组件向父组件传值”的通信手段,但它不触发响应式依赖收集(除非父模板中真正读取了 props)。它的价值不在传值本身,而在渲染权移交。
- 插槽内容的响应性取决于父组件模板如何使用传入的数据,而非子组件是否用了 ref
-
v-slot只能在直接子元素上使用(即必须紧贴组件标签),不能放在普通 div 里再包一层 - 默认插槽名
default可省略,但具名插槽必须显式声明名称,且子组件<slot name="xxx"></slot>要匹配 - 多个作用域插槽可共存,例如同时暴露
header、body、footer并各自传不同数据
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











