h函数三个核心参数依次为type(必需,如字符串或组件)、props(建议显式传null或{},含属性/props/事件)、children(类型依type而定:原生标签为文本/数组,组件为插槽对象)。

h 函数的三个核心参数怎么填
h 函数本质是 Vue 提供的 createVNode 工厂函数,用于手动构造虚拟节点(VNode)。它严格接受且仅接受三个参数,顺序不可变:
-
type:必需。可以是字符串(如
"div"、"button")、组件对象(如Welcome)、异步组件、函数式组件,甚至是一个返回 VNode 的渲染函数。 -
props:可选但强烈建议显式传入(开发时若无属性,应传
null或空对象{})。该对象统一承载:
– HTML 原生属性(id、class、style)
– 组件 props(msg、num)
– 事件监听器(必须用onXxx格式,如onClick、onInput) -
children:类型取决于
type:
– 若type是原生标签,children可为字符串、数组(含多个 VNode)、或纯文本节点;
– 若type是组件,children应为插槽对象({ default: () => [...], header: () => h("h2", "标题") }),而非普通子节点。
原生标签与组件的 children 区别要分清
这是新手最容易混淆的地方:同一个参数位置,在不同 type 下语义完全不同。
- 对
h("p", {}, "Hello"),第三个参数是文本子节点; - 对
h(Welcome, { msg: "Hi" }, { default: () => h("span", "插槽内容") }),第三个参数是插槽定义对象; - 误把组件当标签写成
h(Welcome, {}, "text"),会导致插槽未被识别,内容不渲染。
Vue 不会自动推断意图——它只按 type 类型查表决定如何解析 children。
构建复杂节点树的关键技巧
真实业务中常需动态嵌套、条件分支、循环生成节点。h 函数完全支持这些逻辑,关键在于把 JavaScript 能力自然融入节点创建流程:
-
条件渲染:直接使用三元或 if-else,例如
condition ? h("div", "显示") : null; -
列表映射:用
map生成 VNode 数组,再作为 children 传入父节点,如:h("ul", todos.map(todo => h("li", todo.text))); -
多根结构:h 函数本身只返回单个 VNode,但可通过包装一层容器(如
h("div", [...]))或使用Fragment(h(Fragment, [...]))实现逻辑上的“无根”结构; -
事件与响应式联动:props 中的
onClick可直接绑定 setup 中的 ref 或 computed,例如:h("button", { onClick: () => count.value++ }, "加一")。
常见陷阱与避坑提醒
看似简单,实操中几个细节极易引发静默失败或运行时错误:
- 忘记给组件传插槽对象,却传了字符串或数组 → 插槽内容不显示;
- props 中混用
click和onClick→ 事件不触发(Vue 3 只认onXxx); - children 为数组时,内部包含
undefined或null→ 渲染异常(建议过滤:list.filter(Boolean).map(...)); - 在非 setup/render 上下文中调用 h(比如普通函数里)→ 缺少响应式上下文,ref 不更新;
- 动态 type 使用未定义变量(如
h(dynamicComp)但dynamicComp为undefined)→ 报错 “Invalid vnode type”。

















