Props 是组件显式声明接收的数据,透传 attribute 是未声明的 class、style、id 等,默认自动落到根元素并智能合并;可通过 inheritAttrs: false 手动控制,$attrs 可显式分配;透传会逐层穿透直至被消费。

Props 和透传 attribute 是两个不同层级的概念:props 是组件显式声明并接收的数据,而透传 attribute 是那些没被声明为 props 或 emits 的属性(如 class、style、id、自定义 data- 属性,以及 v-on 监听器),它们默认会“穿过”组件,自动落到根元素上。
透传 attribute 的自动继承规则
当组件模板只有一个根元素时,所有未声明的 attribute 会自动添加到该根节点。比如:
-
<MyButton class="primary" data-id="123" @click="handleClick"></MyButton>中,class、data-id、@click都未在MyButton中声明为 prop 或 emits,就会透传到其内部的<button>上; - 如果根元素本身已有
class="btn",最终渲染结果是class="btn primary"—— Vue 会智能合并,不是覆盖; - 同理,
style也会合并对象形式的样式,例如父级传:style="{ color: 'red' }",子组件根元素有style="font-size: 14px",最终两者都会生效。
透传与 props 的边界在哪
一个属性是否透传,取决于它是否被当前组件“消费”:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 若组件用
defineProps(['size', 'disabled'])声明了 props,那么size和disabled就不会透传,而是由组件内部逻辑处理; - 若用了
defineEmits(['update:modelValue']),那么@update:modelValue就不会作为事件监听器透传下去; - 但
@change、@focus、title、tabindex这类未声明的,仍会透传到根元素。
如何手动控制透传行为
默认自动透传很方便,但有时需要干预:
- 设
inheritAttrs: false(或在<script setup>中用defineOptions({ inheritAttrs: false }))可关闭自动继承; - 关闭后,所有透传 attribute 会收进
$attrs对象(或组合式 API 中的useAttrs()); - 你就可以把它们显式分配给非根元素,比如把
class加到内部<span>上,把@click绑到包装<div>上,而不是默认的按钮。
深层组件链中的透传流转
透传不是只传一层 —— 它会逐级向下“穿透”,直到遇到明确消费它的组件:
-
<App> → <Modal> → <BaseDialog> → <dialog>; - 只要中间每个组件都没声明
class或绑定@click,这些 attribute 就一路透传到底层原生<dialog>元素; - 一旦某层(比如
BaseDialog)把class声明为 prop,那它就“截停”了这个透传,后续组件收不到该 class(除非BaseDialog主动把它再传给<dialog>)。

















