feat(runtime-core): support creating vnode from existing vnode

This allows passing vnode around with curried props and use it in
places where VNodeType is expected, e.g. `<component :is=""/>`
This commit is contained in:
Evan You 2020-07-01 19:48:01 -04:00
parent 359b4a30ca
commit c9629f2692
2 changed files with 26 additions and 3 deletions

View File

@ -42,6 +42,20 @@ describe('vnode', () => {
expect(vnode.props).toBe(null)
})
test('create from an existing vnode', () => {
const vnode1 = createVNode('p', { id: 'foo' })
const vnode2 = createVNode(vnode1, { class: 'bar' }, 'baz')
expect(vnode2).toMatchObject({
type: 'p',
props: {
id: 'foo',
class: 'bar'
},
children: 'baz',
shapeFlag: ShapeFlags.ELEMENT | ShapeFlags.TEXT_CHILDREN
})
})
test('vnode keys', () => {
for (const key of ['', 'a', 0, 1, NaN]) {
expect(createVNode('div', { key }).key).toBe(key)

View File

@ -290,7 +290,7 @@ export const createVNode = (__DEV__
: _createVNode) as typeof _createVNode
function _createVNode(
type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
type: VNode | VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
props: (Data & VNodeProps) | null = null,
children: unknown = null,
patchFlag: number = 0,
@ -304,6 +304,10 @@ function _createVNode(
type = Comment
}
if (isVNode(type)) {
return cloneVNode(type, props, children)
}
// class component normalization.
if (isFunction(type) && '__vccOpts' in type) {
type = type.__vccOpts
@ -406,7 +410,8 @@ function _createVNode(
export function cloneVNode<T, U>(
vnode: VNode<T, U>,
extraProps?: Data & VNodeProps
extraProps?: Data & VNodeProps | null,
children?: unknown
): VNode<T, U> {
const props = extraProps
? vnode.props
@ -415,7 +420,7 @@ export function cloneVNode<T, U>(
: vnode.props
// This is intentionally NOT using spread or extend to avoid the runtime
// key enumeration cost.
return {
const cloned: VNode<T, U> = {
__v_isVNode: true,
__v_skip: true,
type: vnode.type,
@ -452,6 +457,10 @@ export function cloneVNode<T, U>(
el: vnode.el,
anchor: vnode.anchor
}
if (children) {
normalizeChildren(cloned, children)
}
return cloned
}
/**