From d10b28ae0eec6d7fb7c2e64aa591d8b01e695ee8 Mon Sep 17 00:00:00 2001 From: terencez Date: Thu, 10 Oct 2019 22:17:16 +0800 Subject: [PATCH] refactor(runtime-core): make h() support single vnode child (#181) --- packages/runtime-core/__tests__/h.spec.ts | 19 +++++++++++++++---- packages/runtime-core/src/h.ts | 21 ++++++++++++++++----- packages/runtime-core/src/vnode.ts | 2 +- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/packages/runtime-core/__tests__/h.spec.ts b/packages/runtime-core/__tests__/h.spec.ts index b71958d8..b55c9f48 100644 --- a/packages/runtime-core/__tests__/h.spec.ts +++ b/packages/runtime-core/__tests__/h.spec.ts @@ -18,8 +18,12 @@ describe('renderer: h', () => { // array expect(h('div', ['foo'])).toMatchObject(createVNode('div', null, ['foo'])) // default slot + const Component = { template: '
' } const slot = () => {} - expect(h('div', slot)).toMatchObject(createVNode('div', null, slot)) + expect(h(Component, slot)).toMatchObject(createVNode(Component, null, slot)) + // single vnode + const vnode = h('div') + expect(h('div', vnode)).toMatchObject(createVNode('div', null, [vnode])) // text expect(h('div', 'foo')).toMatchObject(createVNode('div', null, 'foo')) }) @@ -28,20 +32,27 @@ describe('renderer: h', () => { // array expect(h('div', {}, ['foo'])).toMatchObject(createVNode('div', {}, ['foo'])) // default slot + const Component = { template: '
' } const slot = () => {} - expect(h('div', {}, slot)).toMatchObject(createVNode('div', {}, slot)) + expect(h(Component, {}, slot)).toMatchObject( + createVNode(Component, {}, slot) + ) + // single vnode + const vnode = h('div') + expect(h('div', {}, vnode)).toMatchObject(createVNode('div', {}, [vnode])) // text expect(h('div', {}, 'foo')).toMatchObject(createVNode('div', {}, 'foo')) }) test('named slots with null props', () => { + const Component = { template: '
' } const slot = () => {} expect( - h('div', null, { + h(Component, null, { foo: slot }) ).toMatchObject( - createVNode('div', null, { + createVNode(Component, null, { foo: slot }) ) diff --git a/packages/runtime-core/src/h.ts b/packages/runtime-core/src/h.ts index 5b32f3b7..eebee368 100644 --- a/packages/runtime-core/src/h.ts +++ b/packages/runtime-core/src/h.ts @@ -4,7 +4,8 @@ import { createVNode, VNodeChildren, Fragment, - Portal + Portal, + isVNode } from './vnode' import { isObject, isArray } from '@vue/shared' import { Ref } from '@vue/reactivity' @@ -34,17 +35,19 @@ h('div', {}) // type + omit props + children // Omit props does NOT support named slots h('div', []) // array -h('div', () => {}) // default slot h('div', 'foo') // text +h('div', h('br')) // vnode +h(Component, () => {}) // default slot // type + props + children h('div', {}, []) // array -h('div', {}, () => {}) // default slot -h('div', {}, {}) // named slots h('div', {}, 'foo') // text +h('div', {}, h('br')) // vnode +h(Component, {}, () => {}) // default slot +h(Component, {}, {}) // named slots // named slots without props requires explicit `null` to avoid ambiguity -h('div', null, {}) +h(Component, null, {}) **/ export interface RawProps { @@ -61,6 +64,7 @@ export type RawChildren = | string | number | boolean + | VNode | VNodeChildren | (() => any) @@ -142,6 +146,10 @@ export function h( ): VNode { if (arguments.length === 2) { if (isObject(propsOrChildren) && !isArray(propsOrChildren)) { + // single vnode without props + if (isVNode(propsOrChildren)) { + return createVNode(type, null, [propsOrChildren]) + } // props without children return createVNode(type, propsOrChildren) } else { @@ -149,6 +157,9 @@ export function h( return createVNode(type, null, propsOrChildren) } } else { + if (isVNode(children)) { + children = [children] + } return createVNode(type, propsOrChildren, children) } } diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 2229fbcd..9abb4476 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -129,7 +129,7 @@ export function createBlock( return vnode } -export function isVNode(value: any): boolean { +export function isVNode(value: any): value is VNode { return value ? value._isVNode === true : false }