插槽内容由父组件编写,但默认插槽和具名插槽在子组件作用域中渲染,作用域插槽则在父组件作用域中执行且接收子组件传递的数据。

Vue 组件插槽的渲染范围和作用域,取决于插槽类型(默认插槽、具名插槽、作用域插槽)以及它被定义和使用的位置。核心原则是:插槽内容的模板由父组件编写,但最终在子组件的上下文中渲染;而作用域插槽的内容则在父组件中执行,且能访问子组件传递的数据。
默认插槽与具名插槽:父写子渲,作用域属于子组件
当你在父组件中写 <MyButton>点击我</MyButton>,这段“点击我”文本作为默认插槽内容,会被 Vue 编译为一个函数(slots.default),传入子组件。子组件内部通过 <slot></slot> 渲染它——此时该内容的响应式数据、方法、计算属性等,全部绑定在子组件实例上,无法直接访问父组件的变量(除非显式透传)。
- 插槽内容中写的
{{ count }},查找的是子组件的count,不是父组件的 - 若想让父组件变量可用,需由子组件通过
props或slot props显式暴露(如<slot :text="title"></slot>) - 具名插槽(如
<template #icon></template>)同样遵循此规则,只是被<slot name="icon"></slot>对应位置接收
作用域插槽(带参数的插槽):父写父渲,数据由子组件提供
作用域插槽本质是子组件向父组件“回调传参”。子组件在 <slot> 上绑定属性(如 <slot :user="userInfo" :index="i"></slot>),父组件用 v-slot:default="{ user, index }" 解构接收。关键点在于:
- 插槽内部的模板(比如
{{ user.name }})是在父组件作用域中编译和执行的 - 所有响应式依赖、
ref、computed都来自父组件,与子组件无关 - 子组件只负责提供数据对象,不参与插槽内容的渲染逻辑
作用域穿透与 v-bind="$attrs"
当子组件封装了更深层的子组件(如 A → B → C),且希望 C 的插槽能访问 A 的数据,不能靠自动继承。常见做法有:
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
立即学习“前端免费学习笔记(深入)”;
- 在中间组件 B 中用
v-bind="$attrs"和inheritAttrs: false透传属性给 C - 或在 B 中显式将需要的数据通过插槽 prop 传给 C(如
<C v-bind="$attrs" :user="userFromA"><template #default="{ user }">...</template></C>) -
$slots默认不会被自动继承,如需转发插槽,B 需显式写<slot name="header"></slot>并确保 C 也接收同名插槽
setup() + script setup 中的插槽行为不变
语法糖不影响作用域本质。即使使用 <script setup>,defineSlots 仅用于类型声明,不改变运行时行为。父组件中写的 v-slot 内容依然按上述规则解析和执行。
理解插槽“谁写、谁编译、谁执行”,就能准确预判数据来源和响应式链路。不复杂但容易忽略。

















