h函数
TIP
h
函数具有多种重载, 可以接受一到多个参数 对参数进行处理并最终调用createVNode
方法创建虚拟节点
官方说法
h
is a more user-friendly version ofcreateVNode
that allows omitting the props when possible.
重载
下面基于h.ts源码对这些重载进行分类讨论
一个参数
ts
// type only
h('div')
创建一个和只有标签类型的VNode
两个参数
标签类型 + props
ts
// type + props
h('div', {})
标签类型 + Children
ts
// type + omit props + children
h('div', []) // children是数组
h('div', 'foo') // children是文本节点
h('div', h('br')) // children是虚拟节点
h(Component, () => {}) // child是默认插槽 不支持具名插槽
三个参数
标签类型 + props + children
ts
// type + props + children
h('div', {}, []) // array
h('div', {}, 'foo') // text
h('div', {}, h('br')) // vnode
h(Component, {}, () => {}) // default slot
h(Component, {}, {}) // named slots
更多参数
会截取两个参数之后的所有参数作为children生成虚拟节点
即
ts
h('div', {}, '1', '2', '3') // => createVNode("div", {}, ["1", "2", "3"])
原理
对参数长度、参数类型做判断并标准化后传入createVNode
ts
export function h(type, propsOrChildren?, children?) {
const l = arguments.length
if (l === 2) {
if (isObject(propsOrChildren) && !Array.isArray(propsOrChildren)) {
// 虚拟节点
if (isVnode(propsOrChildren)) {
// h("div", h("a"))
return createVnode(type, null, [propsOrChildren])
}
else {
// 属性
return createVnode(type, propsOrChildren)
}
}
return createVnode(type, null, propsOrChildren)
}
else {
if (l > 3) {
children = Array.from(arguments).slice(2)
}
if (l === 3 && isVnode(children)) {
children = [children]
}
// == 3 | == 1
return createVnode(type, propsOrChildren, children)
}
}