第一步
h 函数主要是用来创建虚拟 DOM的,他的参数情况比较多,参数情况可以有 1个(类型),2个(类型,属性/儿子),3个(类型, 属性, 儿子),超过 3 个(从第三个开始后面都是儿子),如下:
1 2 3
| h(类型) h(类型, 属性, 儿子) h(类型, 儿子)
|
两个参数的情况:
1. 两个参数的时候,第二个参数可能是属性,或者虚拟节点(根据 `__v_isVnode` 来判断)
1. 第二个参数的数组的话,那第二个参数肯定是儿子
1. 直接传递非对象的话,那说明就是文本
1. 其他情况下,就都是属性
三个参数的时候,第二个参数必须是属性
packages/runtime-core/src/h.ts
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
| import { isObject } from '@vue/shared'; import { createVnode, isVnode } from './createVnode';
export function h(type, propsOrChildren?, children?) { const l = arguments.length; if (l === 2) { if (isObject(propsOrChildren) && !Array.isArray(propsOrChildren)) { if (isVnode(propsOrChildren)) { 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 ]; }
return createVnode(type, propsOrChildren, children); } }
|
packages/runtime-core/src/createVnode.ts
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
| import { isString, ShapeFlags } from '@vue/shared';
export function createVnode(type, props, children?) { const shapeFlag = isString(type) ? ShapeFlags.ELEMENT : 0; const vnode = { __v_isVnode: true, type, props, children, key: props?.key, el: null, shapeFlag };
if (children) { if (Array.isArray(children)) { vnode.shapeFlag = vnode.shapeFlag | ShapeFlags.ARRAY_CHILDREN; } else { children = String(children); vnode.shapeFlag |= ShapeFlags.TEXT_CHILDREN; } } return vnode; }
export function isVnode(value) { return value?.__v_isVnode; }
export function isSameVnode(n1, n2) { return n1.type === n2.type && n1.key === n2.key; }
export const Text = Symbol('text'); export const Fragment = Symbol('Fragment');
|
packages/shared/src/index.ts
1 2 3 4 5
| ... export function isString(value) { return typeof value === 'string'; } ...
|