useslots 和 useattrs 是 vue3 组合式 api 中用于逻辑层处理插槽与非 props 属性的关键函数:前者返回插槽渲染函数,后者返回未声明的响应式属性对象,适用于条件判断、透传或封装高阶组件场景。

在 Vue3 组合式 API 中,useSlots 和 useAttrs 是两个轻量但关键的运行时函数,用于在 <script setup></script> 中访问插槽内容和非 props 属性。它们不是模板语法的替代品,而是在逻辑层需要主动判断、处理或透传时才真正派上用场。
useSlots:拿到插槽的“渲染函数”,不是 DOM
useSlots() 返回一个对象,每个键对应一个插槽名(如 default、header),值是**返回 VNode 数组的函数**。它不提供真实 DOM,也不能直接操作样式或尺寸。
- 检查插槽是否存在:
if (slots.footer)或更稳妥地写if (slots.footer?.())(调用后有返回值才说明存在) - 动态渲染插槽内容:
slots.header?.()可以在 setup 中参与条件逻辑,比如决定是否包裹一层容器 - 作用域插槽数据需在模板中解构,setup 中无法直接读取传递的 props;但可通过
slots.default?.({ data: 'xxx' })手动传入(较少用)
useAttrs:获取未被声明为 props 的所有属性
useAttrs() 返回一个响应式对象,包含所有父组件绑定在子组件标签上、但未被 defineProps 声明的 attribute,比如 class、style、id、自定义属性,甚至 @click 这类事件监听器。
- 常用于“属性透传”:在子组件根元素上使用
v-bind="attrs",让 class/style/事件等自动落到真实 DOM 上 - 可过滤或合并属性:比如剔除某个特定属性
const { onClick, ...rest } = attrs,再把rest透传 - 注意:如果子组件有多个根节点,attrs 不会自动透传,必须手动分配到某个元素上
配合 ref 获取插槽内容的真实 DOM
想操作插槽渲染后的 DOM(比如测高度、加事件),不能靠 useSlots,得靠透传 + ref:
- 子组件用
<slot v-bind="attrs"></slot>,把父组件传的ref透传给插槽内容的最外层元素 - 父组件直接写
<child ref="target"><div>内容</div></child>,这个ref就会指向插槽内容里的<div> <li>若插槽内容没有单个根元素(比如写了多个同级标签),则透传失效,此时需让父组件自己加 <code>ref,或子组件用defineExpose暴露内部 DOM 查询方法
常见误区提醒
这两个函数不是必须使用的。多数场景下,你完全可以在模板里用 $slots 和 $attrs,或者靠透传和默认行为完成需求。只有当你要在 JavaScript 逻辑中做判断、组合、过滤或封装高阶行为时,才需要它们。
比如写一个通用卡片组件,要根据是否有 header 插槽决定是否渲染 header 区域;又或者做一个表单包装器,要把所有未声明的属性(包括 @change)原样透传给内部的 <input> —— 这些才是它们的典型战场。










