Props仅接收显式声明的输入,未声明属性(如class、style、id、placeholder、@click等)默认通过$attrs透传至根元素;设inheritAttrs: false后需手动v-bind="$attrs"分发到内部元素。

Vue 中的 Props 本身不处理原生 HTML 属性的自动继承——那是 $attrs 和 inheritAttrs 的职责。Props 只负责接收你显式声明的输入,而 class、style、id、placeholder、@click 这类未被 props 声明的属性,会自动进入透传通道,默认挂到组件的根元素上。
哪些属性会被自动继承?
只要没在 defineProps(或 props: {})里声明,以下属性都会被 Vue 视为“透传 attribute”,默认落到根元素:
- 通用 DOM 属性:class、style、id、title、tabindex、data-*、aria-*
- 布尔属性:disabled、readonly、required、hidden —— 存在即生效,不关心值
- 原生事件监听器:@click、@input、@focus、@keydown 等(仅限原生事件,不含自定义事件)
- 表单相关属性:placeholder、maxlength、autocomplete、minlength、pattern 等
为什么 class 和 style 会合并而不是覆盖?
Vue 对这两个属性做了特殊处理:
分析 Vue 3 Composition API 使用情况——审计响应式模式、可组合函数设计、ref 与 reactive 的选择、计算属性、watcher 使用及组件……
- 如果根元素已有
class="btn",父组件传class="primary small",最终渲染为class="btn primary small" - 如果根元素有
style="font-size: 14px",父组件传:style="{ color: 'red' }",两者样式会合并生效,不是互相替换
如何把透传属性送到内部元素,而不是根节点?
这是最常见的封装需求(比如 <AppInput> 需要把 placeholder 传给内部 <input>,而不是外层 <div>):
立即学习“前端免费学习笔记(深入)”;
- 在组件中设置
inheritAttrs: false(选项式 API)或defineOptions({ inheritAttrs: false })(组合式 API) - 用
useAttrs()(<script setup>)或this.$attrs(选项式)拿到所有未声明属性 - 手动绑定到目标元素:
<input v-bind="$attrs" />—— 注意这里会包含 class/style/@click 等全部内容
同名 prop 和透传 attr 冲突时谁优先?
明确规则:已声明的 props 永远优先于 $attrs 中同名字段。
- 若子组件写了
defineProps(['size']),父组件传<MyBtn size="large">,则size进入 props,不会出现在$attrs中 - 若父组件还传了
data-id="123",而子组件没声明dataId,那它就会进$attrs,可手动分发


















