Slots 是 Vue 组件灵活复用的核心机制,通过默认插槽、作用域插槽、具名插槽、动态插槽及与 provide/inject 配合,实现逻辑与视图分离、多层上下文传递和高阶组件可定制化。

Slots 是 Vue 中实现组件灵活复用的核心机制,尤其在封装高阶组件(HOC)时,它能将“结构控制权”交还给使用者,避免过度抽象导致的僵化。
默认 Slot + 作用域 Slot:让容器组件只管逻辑,不管渲染
高阶组件常负责数据获取、状态管理、权限校验等横切逻辑,而具体展示形式应由业务决定。通过 <slot> 和 <slot :xxx="value">,可把处理后的数据、方法、加载状态透出给父组件定制 UI。
- 默认 slot 用于接管整个内容区域,适合布局型 HOC(如
ModalWrapper、PageLayout) - 作用域 slot(v-slot:xxx 或 #xxx)用于传递内部状态,比如
loading、data、refetch,让调用方自由组合按钮、骨架屏、空状态 - 示例:一个
AsyncData组件,内部发起请求,通过<slot :data="data" :loading="loading" :error="error" :refetch="refetch"></slot>暴露能力,业务侧可写成<template #default="{ data, loading }">{{ loading ? '加载中' : data.name }}</template>
具名 Slot 分离关注点,提升组合自由度
当高阶组件承载多个可定制区域(如头部操作区、主体内容、底部工具栏),用具名 slot 能清晰划分职责,避免用 props 传一堆渲染函数或 VNode。
- 例如封装一个
TableWithSearch,可提供header、toolbar、body、empty等 slot 名称 - 调用时按需覆盖:
<template #toolbar><SearchInput v-model="q"/></template>,其余区域保持默认 - 比用
renderHeader、renderEmpty等 props 更直观,也天然支持响应式更新和事件绑定
动态 Slot 名 + v-bind="$attrs":构建真正可插拔的壳组件
对于需要适配多种上下文的壳组件(如表单包装器、权限守卫组件),可结合 v-bind="$attrs" 透传属性,并用 v-slot:[slotName] 动态决定插槽名,实现运行时配置。
立即学习“前端免费学习笔记(深入)”;
-
$attrs让父组件传入的非 prop 属性(如title、mode)自动流入子组件,再配合v-slot:[title + 'Header']可动态匹配 slot - 适合做平台级组件库:同一
CardWrapper组件,根据type="user"自动查找#userHeader,type="order'则找#orderHeader - 注意:动态 slot 名需确保命名安全,建议加前缀或白名单校验,避免执行任意字符串
与 provide/inject 配合:跨多层 Slot 传递上下文
当 slot 内容嵌套较深(如 Form > Field > Input),单纯靠作用域 slot 逐层透传会冗余。此时可用 provide 在高阶组件内注入上下文,子组件用 inject 消费,slot 内容自然获得统一状态。
- 例如
FormProvider提供submit、errors、isSubmitting,所有子孙Field、SubmitButton即使写在 slot 里也能响应式访问 - 相比反复绑定
:form-context="ctx",更轻量且解耦,特别适合表单、表格、树形控件等复杂场景 - 注意 provide 的响应性:推荐 provide reactive 对象或 computed,而非普通对象字面量


















