vue3-yuanma/packages/runtime-core/src/vnode.ts

121 lines
2.9 KiB
TypeScript
Raw Normal View History

2019-05-28 13:27:31 +08:00
import { isArray, isFunction } from '@vue/shared'
2019-05-28 19:36:15 +08:00
import { ComponentInstance } from './component'
2019-05-28 17:19:47 +08:00
import { HostNode } from './createRenderer'
2019-05-28 10:28:25 +08:00
2019-05-25 23:51:20 +08:00
export const Fragment = Symbol('Fragment')
export const Text = Symbol('Text')
export const Empty = Symbol('Empty')
2019-05-28 17:19:47 +08:00
export const Portal = Symbol('Portal')
2018-09-19 23:35:38 +08:00
2019-05-25 23:51:20 +08:00
type VNodeTypes =
| string
| Function
2019-05-28 17:19:47 +08:00
| Object
2019-05-25 23:51:20 +08:00
| typeof Fragment
| typeof Text
| typeof Empty
2018-09-19 23:35:38 +08:00
2019-05-28 17:19:47 +08:00
type VNodeChildAtom = VNode | string | number | null | void
export interface VNodeChildren extends Array<VNodeChildren | VNodeChildAtom> {}
export type VNodeChild = VNodeChildAtom | VNodeChildren
2018-10-13 07:49:41 +08:00
2019-05-25 23:51:20 +08:00
export interface VNode {
type: VNodeTypes
props: { [key: string]: any } | null
key: string | number | null
children: string | VNodeChildren | null
2019-05-28 19:36:15 +08:00
component: ComponentInstance | null
2019-05-28 13:27:31 +08:00
// DOM
2019-05-28 17:19:47 +08:00
el: HostNode | null
anchor: HostNode | null // fragment anchor
2019-05-28 13:27:31 +08:00
// optimization only
2019-05-25 23:51:20 +08:00
patchFlag: number | null
dynamicProps: string[] | null
dynamicChildren: VNode[] | null
2018-10-13 07:49:41 +08:00
}
2019-05-27 13:48:40 +08:00
const blockStack: (VNode[] | null)[] = []
2018-09-19 23:35:38 +08:00
2019-05-25 23:51:20 +08:00
// open block
2019-05-27 13:48:40 +08:00
export function openBlock(disableTrackng?: boolean) {
blockStack.push(disableTrackng ? null : [])
2019-05-25 23:51:20 +08:00
}
2018-10-13 07:49:41 +08:00
2019-05-25 23:51:20 +08:00
let shouldTrack = true
2018-10-13 07:49:41 +08:00
2019-05-25 23:51:20 +08:00
// block
export function createBlock(
type: VNodeTypes,
props?: { [key: string]: any } | null,
children?: any,
patchFlag?: number,
dynamicProps?: string[]
): VNode {
// avoid a block with optFlag tracking itself
shouldTrack = false
const vnode = createVNode(type, props, children, patchFlag, dynamicProps)
shouldTrack = true
2019-05-27 13:48:40 +08:00
const trackedNodes = blockStack.pop()
vnode.dynamicChildren =
trackedNodes && trackedNodes.length ? trackedNodes : null
2019-05-25 23:51:20 +08:00
// a block is always going to be patched
trackDynamicNode(vnode)
return vnode
2018-10-13 01:42:19 +08:00
}
2019-05-25 23:51:20 +08:00
// element
export function createVNode(
type: VNodeTypes,
props: { [key: string]: any } | null = null,
children: any = null,
patchFlag: number | null = null,
dynamicProps: string[] | null = null
): VNode {
const vnode: VNode = {
type,
props,
key: props && props.key,
children,
2019-05-28 13:27:31 +08:00
component: null,
2019-05-27 13:48:40 +08:00
el: null,
anchor: null,
2019-05-25 23:51:20 +08:00
patchFlag,
dynamicProps,
dynamicChildren: null
2018-09-19 23:35:38 +08:00
}
2019-05-28 10:28:25 +08:00
if (shouldTrack && (patchFlag != null || isFunction(type))) {
2019-05-25 23:51:20 +08:00
trackDynamicNode(vnode)
2018-09-25 07:11:14 +08:00
}
2019-05-25 23:51:20 +08:00
return vnode
}
2018-09-19 23:35:38 +08:00
2019-05-25 23:51:20 +08:00
function trackDynamicNode(vnode: VNode) {
const currentBlockDynamicNodes = blockStack[blockStack.length - 1]
2019-05-27 13:48:40 +08:00
if (currentBlockDynamicNodes != null) {
2019-05-25 23:51:20 +08:00
currentBlockDynamicNodes.push(vnode)
2018-09-19 23:35:38 +08:00
}
2019-05-25 23:51:20 +08:00
}
2018-09-19 23:35:38 +08:00
2019-05-25 23:51:20 +08:00
export function cloneVNode(vnode: VNode): VNode {
// TODO
return vnode
2019-05-25 23:51:20 +08:00
}
2019-05-28 13:27:31 +08:00
2019-05-28 17:19:47 +08:00
export function normalizeVNode(child: VNodeChild): VNode {
2019-05-28 13:27:31 +08:00
if (child == null) {
// empty placeholder
return createVNode(Empty)
} else if (isArray(child)) {
// fragment
return createVNode(Fragment, null, child)
} else if (typeof child === 'object') {
// already vnode
return child as VNode
} else {
// primitive types
return createVNode(Text, null, child + '')
}
}