一、前言:为什么要关注 Vue3 的 $attrs 变化?
在 Vue 组件开发中,props 穿透(借助 $attrs 传递未声明的属性)是高频场景——比如封装通用按钮、输入框组件时,需要将父组件传递的额外属性(如 placeholder、disabled)透传给子组件内部的原生元素。
而 Vue3 对 attrs的改动堪称“颠覆性”,最核心的一点就是:∗∗class和style不再被attrs 过滤,会直接包含在 $attrs 中并透传**。这和 Vue2 的行为完全相反,也是很多开发者迁移项目、编写新组件时最容易踩坑的点,掌握这个变化能少走大量弯路。
二、Vue2 vs Vue3:$attrs 核心差异对比(重点!)
要理解这个变化,先明确 Vue2 中 $attrs 的行为,再对比 Vue3 的改动,差异一目了然,避免混淆。
1. Vue2 中的 $attrs 行为
在 Vue2 中,$attrs 有一个明确的“过滤规则”:
- 仅包含父组件传递给子组件、但子组件未通过 props 声明的非 class、非 style 属性;
- class 和 style 会被单独提取,直接应用到子组件的根元素上,不会出现在 $attrs 中;
- 若想手动控制 class/style 透传,需借助 inheritAttrs: false 关闭默认透传,但即便关闭,$attrs 依然不包含 class/style。
2. Vue3 中的 $attrs 行为(核心变化)
Vue3 彻底简化了这一逻辑,同时改变了 $attrs 的包含范围:
- 核心变化:$attrs 不再过滤 class 和 style,会将父组件传递的所有未被 props 声明的属性(包括 class、style)全部包含在内;
- 默认透传行为不变:未声明的 props(含 class/style)依然会自动透传至子组件的根元素;
- inheritAttrs: false 的作用升级:关闭默认透传后,class 和 style 也会跟随 attrs一起被“拦截”,不会再自动应用到根元素,需手动通过v−bind="attrs" 控制透传位置。
- Vue2 中:$attrs = { disabled: true }(class、style 被过滤,直接应用到子组件 button 上);
- Vue3 中:attrs=class:"btn−primary",style:padding:"10px",disabled:true(class、style被包含在attrs 中,同时自动透传至 button 上)。
4. inheritAttrs: false 后的差异(关键避坑点)
当子组件设置 inheritAttrs: false 后,两者的差异更明显:
- Vue2 中:class、style 依然会自动应用到子组件根元素(button),仅未声明的 props(disabled)被拦截在 $attrs 中;
- Vue3 中:class、style 会和 disabled 一起被拦截在 attrs中,∗∗不再自动应用到根元素∗∗,需手动写<buttonv−bind="attrs"> 才能将所有属性(含 class/style)透传。
四、常见踩坑场景及解决方案
掌握变化后,重点解决实际开发中最易遇到的 2 个坑,新手直接套用即可。
坑点1:子组件根元素不需要 class/style 透传
场景:父组件传递的 class/style 是给子组件内部某个非根元素用的,根元素有自己的样式,不想继承父组件的 class/style。
解决方案:
- 子组件设置 inheritAttrs: false,关闭默认透传;
- 通过解构赋值,从 $attrs 中剔除 class 和 style,再将剩余属性透传给目标元素。
<!-- 子组件 Child.vue(Vue3) -->
<template>
<div class="child-root">
<button v-bind="restAttrs">测试按钮</button>
</div>
</template>
<script setup>
import { useAttrs } from 'vue'
const props = defineProps(['title'])
const attrs = useAttrs()
const { class: _, style: __, ...restAttrs } = attrs
</script>
坑点2:手动透传 $attrs 导致 class/style 重复
场景:未关闭 inheritAttrs,又手动写 v-bind="$attrs",导致 class/style 被重复应用(根元素会同时拥有默认透传和手动透传的样式)。
解决方案:
- 要么不手动透传,依赖默认透传行为;
- 要么设置 inheritAttrs: false,再手动透传 $attrs(按需剔除多余属性)。
五、总结:Vue3 $attrs 变化核心要点
无需死记硬背,记住 3 个核心要点,轻松应对所有场景:
- 包含范围变化:Vue3 $attrs 包含 class/style,Vue2 不包含;
- 默认透传:两者一致,未声明的 props(含 class/style)自动透传至根元素;
- inheritAttrs 作用:Vue3 中关闭后,class/style 会被一同拦截,需手动控制透传。
Vue3 对 $attrs 的改动,本质是简化了属性透传的逻辑,让开发者能更灵活地控制属性传递,但也带来了新的踩坑点。掌握本文的差异对比和实操方案,就能轻松规避风险,高效运用 props 穿透开发 Vue3 组件~