Skip to content

h函数

TIP

h函数具有多种重载, 可以接受一到多个参数 对参数进行处理并最终调用createVNode方法创建虚拟节点

官方说法

h is a more user-friendly version of createVNode 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)
  }
}