<p>Vue 3 渲染器区分 prop 与 attribute:声明的 props 属于组件内部契约,不透传;未声明属性(如 placeholder)作为透传 attribute 自动注入根元素,class/style/value 等按 DOM property 更新,data-* 等走 setAttribute。</p>

Vue 3 渲染器在处理 prop 时,并不直接操作 HTML 特性(attribute),而是通过 DOM 属性(property)与虚拟节点(VNode)的 props 字段协同工作。这种设计源于 HTML 特性与 DOM 属性本质不同——特性是字符串化的初始声明,属性是运行时可读写的对象字段。
HTML 特性 vs DOM 属性:渲染器如何区分
当一个 prop 映射到原生元素(如 <input :value="msg">)时,Vue 渲染器会做智能判断:
-
对
value、checked、selected等有对应 DOM 属性的 prop:优先设置el.value/el.checked,而非调用setAttribute,确保表单控件状态准确、可响应用户交互 -
对
class、style等复合特性:解析为对象或数组后,交由专门的 patch 逻辑更新el.className或el.style.cssText,兼顾性能与语义 -
对自定义特性(如
data-id、aria-label):走标准的setAttribute流程,因为它们没有对应的 DOM 属性 -
对布尔特性(如
disabled):值为falsy(false、null、undefined)时移除该特性;值为true或非空字符串时设置setAttribute('disabled', ''),符合 HTML 规范
组件 Prop 不参与特性透传的边界
渲染器明确区分“组件 prop”和“透传 attribute”:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 显式声明在
defineProps中的字段,属于组件内部数据契约,不会自动落到根元素上 - 未被声明的属性(且未被
v-bind="$attrs"消费),才作为透传 attribute 由渲染器注入子组件根节点 - 这意味着
<MyInput :size="sm" placeholder="请输入"></MyInput>中,size是组件 prop,placeholder默认成为透传 attribute —— 渲染器按此规则分别路由,互不干扰
动态绑定如何影响属性/特性选择
是否带冒号(: 或 v-bind:)决定 Vue 渲染器走哪条路径:
立即学习“前端免费学习笔记(深入)”;
-
<div class="btn">→ 静态,走setAttribute('class', 'btn') -
<div :class="['btn', isActive ? 'active' : '']">→ 动态,转为className属性更新,同时触发 class 列表 diff -
<input :value="text">→ 绑定到el.value,支持用户输入后仍能响应式同步 -
<input value="text">→ 仅设初始特性,后续响应式更新无效,等同于只读
为什么这个区别影响实际开发
理解这一机制能避开常见陷阱:
- 想让子组件控制
input值?必须用:value+@input实现双向绑定,而不是value特性 - 给第三方库组件传
data-*属性?确保没被defineProps声明,否则会被吞掉,不会出现在 DOM 上 - 封装按钮组件时,
disabled应声明为 prop 并手动绑定到根<button>,否则布尔逻辑失效

















