h函数是createVNode的轻量封装,通过运行时参数判断与归一化实现多参数灵活性:2参数为type+props,3参数含children,4+参数合并children;props和children均经标准化处理。

Vue.js 的 h 函数本身不执行“底层转换逻辑”,它只是一个轻量级的、约定俗成的创建虚拟 DOM 节点(VNode)的工厂函数。 它的多参数灵活性来源于对参数数量、类型和顺序的**运行时判断与归一化处理**,而非编译期转换或隐式重写。核心在于:Vue 内部通过统一的 createVNode(v3)或 createElementVNode(v3.4+)来承接所有调用,并在其中完成参数标准化。
参数数量与位置决定参数语义
h 是一个高度重载的函数,其行为由传入参数的个数和类型动态推断:
-
2 个参数:
h('div', { id: 'app' })→ 视为type + props,子节点为空数组 -
3 个参数:
-
h('span', { cls: 'red' }, 'hello')→type + props + children(字符串/数组/VNode) -
h('ul', [h('li', 'a'), h('li', 'b')])→ 若第二个参数是数组且无对象 props,则自动将该数组视为children,props 设为null
-
-
更多参数(如 4 个):
h('div', {}, 'a', 'b')→ 第三个及之后参数被合并为children数组(支持多子节点扁平化)
props 对象的隐式规范化
当传入 props 对象时,Vue 会做轻量但关键的识别:
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
- 若 props 中存在
class或style字段,它们会被单独提取并深度归一化(例如支持数组、对象、响应式对象等格式),再挂载到 VNode 的cls/style属性上 - 以
on开头的 key(如onClick)被识别为事件监听器,自动转为小写驼峰并注册到handlers字段 - 普通属性(如
id、disabled)直接透传为 DOM 属性,布尔值属性按真实值渲染(false不渲染,null/undefined被忽略)
children 的自动扁平与类型适配
Vue 对 children 做了鲁棒性处理,避免用户手动 flat():
立即学习“前端免费学习笔记(深入)”;
- 字符串、数字、null、undefined → 自动包装为文本 VNode
- VNode 实例 → 直接保留
- 数组 → 递归扁平(支持多层嵌套数组),过滤掉空值(
null/undefined/false) - 对象(非 VNode)→ 若有
__v_isVNode: true标识则视为合法 VNode;否则抛错或静默忽略(取决于开发模式)
本质是 createVNode 的封装,不是语法糖转换
h 函数在源码中几乎就是 createVNode 的一层薄封装(见 packages/runtime-core/src/h.ts):
- 它不做 AST 解析、不生成新函数、不修改用户传参结构
- 所有“多种格式”支持,都靠
createVNode内部的normalizeChildren和normalizeProps工具函数完成 - 开发时看到的“灵活调用”,其实是 Vue 运行时对常见使用模式的主动适配,目的是降低手写 render 函数的心智负担

















