Vue.js 的 h 函数对属性执行归一化处理:props 与 attrs 按组件声明自动分离;class/style 深度合并并统一格式;事件监听器标准化(onXxx→小写键+修饰符解析);ref/key/modelValue 等特殊 prop 被优先拦截转换。

Vue.js 中 h 函数生成 VNode 时,并不会直接把传入的属性原样塞进 VNode 对象,而是经过一套明确的属性归一化(normalization)与规范化(normalization + normalization-aware handling)流程。这个过程决定了 props、attrs、事件、class、style 等如何被识别、合并、过滤和挂载,直接影响组件行为与渲染结果。
props 与 attrs 的自动分离
当调用 h(Component, { onClick: handler, id: 'foo', disabled: true }) 时,Vue 会依据组件的 props 定义(或运行时推导)判断哪些属性属于显式声明的 prop,其余则归入 attrs:
- 若组件定义了
props: ['id', 'disabled'],则id和disabled进入props字段,onClick被识别为事件监听器,进入props.on或props.onClick(取决于 Vue 版本与写法) - 若组件未声明
id,但传入了id,它将落入attrs.id,并默认透传到根元素(除非禁用inheritAttrs: false) - 原生 DOM 事件(如
onClick、onInput)会被自动转为小写onclick并作为原生监听器绑定;而自定义事件(如onUpdate:modelValue)保留 PascalCase 形式,供emit触发
class 与 style 的深度合并策略
class 和 style 是特殊处理的属性,支持多种格式输入并自动归一化为统一结构:
根据 package.json 中的 engines 字段自动检测 Node.js 版本需求,未安装 nvm 时自动安装并切换至对应版本。支持 Windows、macOS、Linux。适用于 Node.js 项目开发、版本切换和环境配置。
-
class支持字符串、对象、数组混合:h('div', { class: ['a', { b: true }, 'c'] })→ 归一化为"a b c";组件内部的class也会与父级传入的合并(非覆盖) -
style支持对象({ color: 'red', fontSize: '14px' })或字符串("color:red;font-size:14px;"),最终统一转为驼峰键的对象,并与组件自身style合并;CSS 变量、重要性(!important)等会被保留但需手动处理 - 归一化后,
class和style都会分别挂载到 VNode 的props.class和props.style,而非attrs
事件监听器的标准化注册
事件名在归一化中经历大小写与命名空间处理:
立即学习“前端免费学习笔记(深入)”;
-
onXxx形式的 prop(如onClick)被识别为事件监听器,key 去掉on前缀并首字母小写(click),值存入props.on.click或props.onClick(Vue 3 使用props.on对象) - 支持修饰符语法糖:如
onClickCapture→{ capture: true };onKeydownEnter→{ key: 'Enter' };这些修饰信息在归一化阶段被解析并附加到事件处理器配置中 - 不带
on前缀的click、input等直接作为原生属性写入attrs,不会被当作事件监听器(除非手动用v-on:click指令)
内置指令与特殊 prop 的拦截与转换
某些属性名具有语义优先级,会在归一化中被提前识别并转换:
-
ref、key、slot、is等属于 VNode 核心字段,直接挂载到 VNode 实例上,不进入props或attrs -
modelValue(Vue 3)或value(Vue 2)配合onUpdate:modelValue会被识别为 v-model 协议,在归一化中合并为props.modelValue与props['onUpdate:modelValue'] -
to、replace、custom等在特定组件(如<RouterLink>)中可能被提取为专用 prop,绕过通用 attrs 逻辑

















