摘要
在实际开发中,经常用到 h 方法来实现页面,常见的组件中也有 render,h 这种写法。例如 iview 的 table 中
![472cbb0b835049e7aae4f.png]()
那么 h 用法也有很多的多样性。例如
h("div",{style:{color: "black"}})
h("div",h('span'))
h('div', [h('span'),h('span)])
h("div","hello")
h("div",null,'hello','world')
h('div',null, h('span'))
h("div",{style:{color: "white"}},'hello')
h("div",hello)
h("div")
源码中 h 主要是调用 createVnode 方法创建虚拟 dom,所以主要的东西在 createVnode,h 就像一个提供方便创造的可能。
编写 createVnode
首先要明白为啥用虚拟节点而不是真实的 dom。虚拟 dom 就是一个对象,为了用于 diff 算法,真实 dom 的属性比较多。
其次虚拟节点的类型有很多,例如组件、元素、文本等。
那么为了判断虚拟 dom 的类型,需要有一个判断类型的方法。
在 shared 编写一个 ShapeFlags 的函数。
1 2 3 4 5 6 7 8 9 10 11 12
| export const enum ShapeFlags { ELEMENT = 1, FUNCTIONAL_COMPONENT = 1 << 1, STATEFUL_COMPONENT = 1 << 2, TEXT_CHILDREN = 1 << 3, ARRAY_CHILDREN = 1 << 4, SLOTS_CHILDREN = 1 << 5, TELEPORT = 1 << 6, SUSPENSE = 1 << 7, COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8, COMPONENT_KEPT_ALIVE = 1 << 9, COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT,
|
这样就有了一个判断传入的孩子节点的类型判断方法了。
为了统一代码的编写,确认孩子的类型,将孩子放在一个数组中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import { isArray, isString, ShapeFlags } from "@vue/shared";
export function createVnode(type, props, children = null) { let shapeFlag = isString(type) ? ShapeFlags.ELEMENT : 0;
const vnode = { type, props, children, el: null, key: props?.["key"], __v_isVnode: true, shapeFlag, };
if (children) { let type = 0; if (isArray(children)) { type = ShapeFlags.ARRAY_CHILDREN; } else { children = String(children); type = ShapeFlags.TEXT_CHILDREN; } vnode.shapeFlag |= type; }
return vnode; }
export function isVnode(value) { return !!(value && value.__v_isVnode); }
|
有了上面创建虚拟节点的方法之后,h 就是一个对写法的支持划分了。
按照上面 h 可以有的写法。编写自己的 h 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
import { isArray, isObject } from "@vue/shared"; import { createVnode, isVnode } from "./vnode";
export function h(type, propsChildren?: any, children?: any) { const l = arguments.length;
if (l === 2) { if (isObject(propsChildren) && !isArray(propsChildren)) { if (isVnode(propsChildren)) { return createVnode(type, null, [propsChildren]); } return createVnode(type, propsChildren); } else { return createVnode(type, null, propsChildren); } } else { if (l > 3) { children = Array.from(arguments).slice(2); } else if (l === 3 && isVnode(children)) { children = [children]; } return createVnode(type, propsChildren, children); } }
|
在上面判断传入参数的个数来区分。同时如果就一个孩子,那么为了写法处理的统一,放入到数组中。
所以最后就 2 种情况
h("h1",{},[])
h("h1",null, 文本)
bookmark