diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts new file mode 100644 index 0000000..e494433 --- /dev/null +++ b/packages/runtime-core/src/h.ts @@ -0,0 +1,25 @@ +import { createVNode, isVNode, VNode } from './vnode' +import { isObject } from '@vue/shared' + +export function h(type: any, propsOrChildren?: any, children?: any): VNode { + const l = arguments.length + if (l === 2) { + //是对象 + if (isObject(propsOrChildren) && !Array.isArray(propsOrChildren)) { + if (isVNode(propsOrChildren)) { + return createVNode(type, null, [propsOrChildren]) + } + return createVNode(type, propsOrChildren, []) + } else { + //是数组 + return createVNode(type, null, propsOrChildren) + } + } else { + if (l > 3) { + children = Array.prototype.slice.call(arguments, 2) //生成新的children + } else if (l === 3 && isVNode(children)) { + children = [children] + } + return createVNode(type, propsOrChildren, children) + } +} diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index c1885a8..a2fbb14 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -1,2 +1,3 @@ export { queuePreFlushCb } from './scheduler' export { watch } from './apiWatch' +export { h } from './h' diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts new file mode 100644 index 0000000..4c5865a --- /dev/null +++ b/packages/runtime-core/src/vnode.ts @@ -0,0 +1,43 @@ +import { isArray, isFunction, isString, ShapeFlags } from '@vue/shared' + +export interface VNode { + __v_isVNode: true + type: any + props: any + children: any + shapeFlag: number +} +export function isVNode(value): value is VNode { + return value ? value.__v_isVNode === true : false +} +export function createVNode(type, props, children): VNode { + const shapeFlag = isString(type) ? ShapeFlags.ELEMENT : 0 + return createBaseVNode(type, props, children, shapeFlag) +} + +function createBaseVNode(type, props, children, shapeFlag) { + const vnode = { + __v_isVNode: true, + type, + props, + shapeFlag + } as VNode + //解析/标准化当前vnode下的children + normalizeChildren(vnode, children) + return vnode +} +export function normalizeChildren(vnode: VNode, children: unknown) { + let type = 0 + const { shapeFlag } = vnode + if (children == null) { + children = null + } else if (isArray(children)) { + } else if (typeof children === 'object') { + } else if (isFunction(children)) { + } else { + children = String(children) + type = ShapeFlags.TEXT_CHILDREN + } + vnode.children = children + vnode.shapeFlag |= type +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index f740520..84dee3c 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,3 +1,4 @@ +export { ShapeFlags } from './shapeFlags' //判断是否为一个数组 export const isArray = Array.isArray @@ -14,6 +15,10 @@ export const isFunction = (val: unknown): val is Function => { return typeof val === 'function' } +export const isString = (val: unknown): val is string => { + return typeof val === 'string' +} + export const extend = Object.assign export const EMPTY_OBJ: { readonly [key: string]: any } = {} diff --git a/packages/shared/src/shapeFlags.ts b/packages/shared/src/shapeFlags.ts new file mode 100644 index 0000000..7a06c3f --- /dev/null +++ b/packages/shared/src/shapeFlags.ts @@ -0,0 +1,30 @@ +export const enum ShapeFlags { + /** + * type=Element + */ + ELEMENT = 1, + /** + * 函数组件 + */ + FUNCTIONAL_COMPONENT = 1 << 1, + /** + * 有状态(响应数据)组件 + */ + STATEFUL_COMPONENT = 1 << 2, + /** + * children=Text + */ + TEXT_CHILDREN = 1 << 3, + /** + * children=Array + */ + ARRAY_CHILDREN = 1 << 4, + /** + * children=slot + */ + SLOTS__CHILDREN = 1 << 5, + /** + * 组件: 有状态(响应数据)组件 | 函数组件 + */ + COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT +} diff --git a/packages/vue/examples/runtime/h-element.html b/packages/vue/examples/runtime/h-element.html new file mode 100644 index 0000000..2752667 --- /dev/null +++ b/packages/vue/examples/runtime/h-element.html @@ -0,0 +1,18 @@ + +
+ + +