插槽 Slot 文章目录前言一、为什么需要插槽1.1 问题1.2 插槽的作用二、默认插槽2.1 基本用法2.2 默认内容三、具名插槽3.1 定义3.2 父组件使用3.3 简写规则四、作用域插槽4.1 定义4.2 父组件使用4.3 具名 作用域插槽五、应用场景5.1 通用卡片组件5.2 布局组件5.3 表格自定义列5.4 对话框组件六、Vue 2 vs Vue 3 语法6.1 变化对照6.2 注意事项七、面试聚焦7.1 插槽内容的编译作用域7.2 作用域插槽 vs 普通插槽7.3 Vue 3 移除 slot-scope八、易混淆点九、思考与练习总结前言插槽Slot是 Vue 的内容分发机制让父组件可以向子组件模板中注入任意内容。本篇会讲清楚默认插槽、具名插槽、作用域插槽v-slot/#简写插槽内容的编译作用域Vue 2 到 Vue 3 的语法变化一、为什么需要插槽1.1 问题!-- 子组件 Card 只能写死内容 -- template div classcard h3固定标题/h3 p固定内容/p /div /template !-- 父组件无法自定义卡片内部内容 -- Card /1.2 插槽的作用插槽允许父组件向子组件注入自定义内容子组件只负责布局和容器内容由父组件决定。!-- 子组件 Card.vue -- template div classcard slot默认内容/slot /div /template !-- 父组件 -- Card h3自定义标题/h3 p自定义内容/p /Card二、默认插槽2.1 基本用法!-- 子组件 MyButton.vue -- template button classbtn slot默认按钮文字/slot /button /template !-- 父组件 -- MyButton提交/MyButton !-- 渲染button classbtn提交/button -- MyButton / !-- 渲染button classbtn默认按钮文字/button --2.2 默认内容slot标签内的内容是后备内容父组件未传入内容时显示slot span暂无内容/span /slot三、具名插槽3.1 定义具名插槽通过name属性区分多个插槽父组件使用v-slot:name或#name指定目标。!-- 子组件 Layout.vue -- template div classlayout header slot nameheader/slot /header main slot/slot !-- 默认插槽 -- /main footer slot namefooter/slot /footer /div /template3.2 父组件使用template Layout !-- 具名插槽v-slot:header 或 #header -- template #header h1页面标题/h1 /template !-- 默认插槽 -- p主要内容区域/p template #footer p© 2026 版权所有/p /template /Layout /template3.3 简写规则!-- 完整写法 -- template v-slot:header标题/template !-- 简写推荐 -- template #header标题/template !-- 默认插槽简写 -- template #default内容/template !-- 或直接写内容省略 template -- Layout内容/Layout四、作用域插槽4.1 定义作用域插槽将子组件的数据通过 props 传递给父组件让父组件控制渲染逻辑。!-- 子组件 List.vue -- script setup defineProps({ items: Array }) /script template ul li v-for(item, index) in items :keyitem.id !-- 向父组件暴露 item 数据 -- slot :itemitem :indexindex {{ item.name }} /slot /li /ul /template4.2 父组件使用template !-- 接收子组件传递的数据 -- List :itemslist v-slot{ item } b{{ item.name }}/b - {{ item.desc }} /List !-- 解构多个 prop -- List :itemslist v-slot{ item, index } {{ index 1 }}. {{ item.name }} /List /template4.3 具名 作用域插槽!-- 子组件 Table.vue -- script setup defineProps({ data: { type: Array, required: true }, columns: { type: Array, required: true } }) /script template table thead tr !-- 向 #header 插槽暴露 columns -- slot nameheader :columnscolumns/slot /tr /thead tbody tr v-forrow in data :keyrow.id !-- 向 #row 插槽暴露当前行数据 -- slot namerow :rowrow/slot /tr /tbody /table /template!-- 父组件 -- script setup const users [ { id: 1, name: Alice, email: aliceexample.com }, { id: 2, name: Bob, email: bobexample.com } ] const columns [姓名, 邮箱] /script template Table :datausers :columnscolumns template #header{ columns } th v-forcol in columns :keycol{{ col }}/th /template template #row{ row } td{{ row.name }}/td td{{ row.email }}/td /template /Table /template说明子组件通过defineProps接收data和columns#header插槽接收子组件传出的columns渲染表头#row插槽在每一行循环中接收row渲染单元格五、应用场景5.1 通用卡片组件!-- Card.vue -- template div classcard div classcard-header slot nameheader默认标题/slot /div div classcard-body slot默认内容/slot /div /div /template !-- 使用 -- Card template #header用户信息/template p姓名Alice/p /Card5.2 布局组件!-- PageLayout.vue -- template div classpage asideslot namesidebar //aside mainslot //main /div /template5.3 表格自定义列!-- DataTable.vue -- template table tr v-forrow in rows :keyrow.id td v-forcol in columns :keycol.key slot :namecol.key :rowrow :valuerow[col.key] {{ row[col.key] }} /slot /td /tr /table /template !-- 父组件自定义某列渲染 -- DataTable :rowsdata :columnscols template #status{ value } span :classvalue{{ value }}/span /template /DataTable5.4 对话框组件!-- Dialog.vue -- template div classdialog div classdialog-header slot nametitle提示/slot /div div classdialog-body slot / /div div classdialog-footer slot namefooter button click$emit(close)关闭/button /slot /div /div /template六、Vue 2 vs Vue 3 语法6.1 变化对照Vue 2Vue 3slotheader#header或v-slot:headerslot-scope{ item }#default{ item }具名 作用域分开写统一用v-slot!-- Vue 2 -- List :itemslist template slotitem slot-scope{ item } {{ item.name }} /template /List !-- Vue 3 -- List :itemslist template #item{ item } {{ item.name }} /template /List6.2 注意事项!-- ❌ v-slot 不能直接用在普通元素上 -- div #header标题/div !-- ✅ 必须用在 template 上 -- template #header标题/template !-- ✅ 默认插槽可以省略 template -- MyComponent直接写内容/MyComponent七、面试聚焦7.1 插槽内容的编译作用域!-- 插槽内容在父组件作用域中编译 -- script setup const parentMsg 来自父组件 /script template Child {{ parentMsg }} !-- ✅ 可以访问父组件数据 -- !-- {{ childMsg }} ❌ 无法访问子组件数据除非作用域插槽 -- /Child /template7.2 作用域插槽 vs 普通插槽// 普通插槽父组件向子组件注入内容// 作用域插槽子组件向父组件暴露数据父组件决定如何渲染// 典型场景表格/List 组件暴露 row 数据父组件自定义列渲染7.3 Vue 3 移除 slot-scope// Vue 2: slot slot-scope 两个属性// Vue 3: 统一 v-slot简写 #语法更一致八、易混淆点插槽内容在父组件作用域编译只能访问父组件的数据和方法不能直接访问子组件内部数据。作用域插槽的数据是只读的父组件不能通过插槽 props 修改子组件内部状态。v-slot 只能用在template上默认插槽内容可以直接写具名/作用域插槽需用 template。Vue 3 移除 slot / slot-scope统一使用v-slot或#简写。默认插槽名是 defaultslot等价于slot namedefault。九、思考与练习1.插槽和普通 Props 传递 HTML 有什么区别解析Props传递数据子组件控制如何渲染插槽传递内容/结构父组件控制渲染什么2.作用域插槽和普通插槽的区别解析普通插槽父 → 子父组件注入内容作用域插槽子 → 父子组件暴露数据父组件决定渲染方式3.插槽内容在哪个作用域编译解析在父组件作用域编译只能访问父组件的数据和方法。需要子组件数据时使用作用域插槽。4.Vue 3 中如何写具名作用域插槽Child v-slot:item{ row } {{ row.name }} /Child !-- 或 -- Child #item{ row } {{ row.name }} /Child5.为什么 v-slot 不能直接用在 div 等元素上解析v-slot是编译时指令用于标记插槽内容边界。Vue 3 要求它用在template上以便编译器正确识别插槽边界默认插槽的内容可以直接写在组件标签内。总结插槽Vue 的内容分发机制父组件向子组件注入内容默认插槽slot父组件直接写内容具名插槽slot namexxx父组件用#xxx指定作用域插槽子组件通过slot :propval暴露数据父组件自定义渲染编译作用域插槽内容在父组件作用域编译Vue 3统一v-slot/#移除 slot-scope