Vue 3 提供的 createElement 工具函数——h
在 Vue 3 的开发中,我们经常会遇到这样一种场景:需要在 渲染函数(render function) 或者 作用域插槽 中,动态生成虚拟 DOM 结构。这时候,就离不开 Vue 3 提供的一个工具函数——h
。它的全称其实就是 createElement
,或者更准确地说是 createVNode
的简写。
本文将从 来源、适用范围、使用方法、实际应用案例 四个方面来介绍 h
的用法。
一、h
的来源
在 Vue 3 中,h
是由 vue
包提供的一个工具函数,用来创建虚拟节点(VNode)。使用时只需要从 vue
中导入:
import { h } from 'vue'
h
的名字来源于 hyperscript,意思是“用 JavaScript 来描述 HTML 结构”。所以你可以把它理解为:用 JS 写 DOM 节点。
二、h
的适用范围
通常情况下,我们写 Vue 组件时都会用模板语法 (<template>
),这样更直观。但是有些场景下模板不够灵活,例如:
渲染函数(render function)
当组件需要完全用 JS 逻辑来控制渲染时,可以用render()
函数返回h
创建的节点。作用域插槽(slots)
在自定义表格列、动态渲染 slot 内容时,常常需要返回h(...)
生成的 VNode。JSX 替代方案
如果项目没配置 JSX,使用h
也能实现相同的效果。
因此,h
主要适用于 需要动态生成结构、模板不方便书写 的场景。
三、h
的使用方法
h
的基本函数签名如下:
h(type: string | Component, // 节点类型,可以是标签名('div'、'span')或组件props?: object | null, // 节点的属性,例如 class、style、事件监听等children?: string | VNode[] // 子节点,可以是字符串、VNode 或 VNode 数组
)
📌 举几个例子:
// 1. 创建一个 <span>Hello Vue3</span>
h('span', null, 'Hello Vue3')// 2. 创建一个 <span class="red">文字红色</span>
h('span', { class: 'red' }, '文字红色')// 3. 创建一个嵌套结构 <div><span>1</span><span>2</span></div>
h('div', null, [h('span', null, '1'),h('span', null, '2')
])
从这些例子可以看到,h
就是用 JavaScript 去描述你原本写在模板里的 DOM 结构。
四、实际应用案例
以表格组件(如 vxe-grid
)的插槽为例,我们可能需要根据数据动态渲染不同内容,并对部分文字加上样式:
slots: {default: ({ row }) => {const priceRange = row.priceMax? `${row.priceMin}~${row.priceMax}`: row.priceMinconst statsNodes = (row.promotionStats || []).map((item, index) =>h('div', { class: 'stat-line' }, `${index + 1}. ${item}`))return h('div', null, [h('span', null, `基准:${row.basePrice ?? ''}`),h('span', { class: 'leftWidth' }, '叠加:'),h('span', { class: 'danger' }, priceRange),...statsNodes])}
}
上面的写法用 h
动态创建了一个 div
容器,里面依次拼接了 span
、div
等节点,并且给 promotionStats
每行都加上了序号。
如果用模板来写,就相当于:
<div><span>基准:{{ row.basePrice }}</span><span class="leftWidth">叠加:</span><span class="danger">{{ priceRange }}</span><div v-for="(item, i) in row.promotionStats" :key="i">{{ i + 1 }}. {{ item }}</div>
</div>
五、和 JSX 的对比
如果你的项目配置了 JSX,那么上面这段代码可以用更直观的方式来写:
slots: {default: ({ row }) => {const priceRange = row.priceMax? `${row.priceMin}~${row.priceMax}`: row.priceMinreturn (<div><span>基准:{row.basePrice}</span><span class="leftWidth">叠加:</span><span class="danger">{priceRange}</span>{row.promotionStats?.map((item, index) => (<div>{index + 1}. {item}</div>))}</div>)}
}
JSX 的好处就是可读性更强,不用反复写 h('span', …)
。
六、总结
h
是 Vue 3 提供的 创建虚拟节点 (VNode) 的工具函数。它的主要用途是:在 渲染函数、插槽函数 中用 JS 来生成 DOM。
h
的写法有些啰嗦,但能提供比模板更高的灵活性。如果项目支持 JSX,可以用 JSX 替代
h
,代码会更直观。
一句话总结:
模板写不出来的复杂结构,就交给
h
吧!