refactor(runtime-core): make h() support single vnode child (#181)

This commit is contained in:
terencez 2019-10-10 22:17:16 +08:00 committed by Evan You
parent b7b89505eb
commit d10b28ae0e
3 changed files with 32 additions and 10 deletions

View File

@ -18,8 +18,12 @@ describe('renderer: h', () => {
// array // array
expect(h('div', ['foo'])).toMatchObject(createVNode('div', null, ['foo'])) expect(h('div', ['foo'])).toMatchObject(createVNode('div', null, ['foo']))
// default slot // default slot
const Component = { template: '<br />' }
const slot = () => {} 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 // text
expect(h('div', 'foo')).toMatchObject(createVNode('div', null, 'foo')) expect(h('div', 'foo')).toMatchObject(createVNode('div', null, 'foo'))
}) })
@ -28,20 +32,27 @@ describe('renderer: h', () => {
// array // array
expect(h('div', {}, ['foo'])).toMatchObject(createVNode('div', {}, ['foo'])) expect(h('div', {}, ['foo'])).toMatchObject(createVNode('div', {}, ['foo']))
// default slot // default slot
const Component = { template: '<br />' }
const slot = () => {} 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 // text
expect(h('div', {}, 'foo')).toMatchObject(createVNode('div', {}, 'foo')) expect(h('div', {}, 'foo')).toMatchObject(createVNode('div', {}, 'foo'))
}) })
test('named slots with null props', () => { test('named slots with null props', () => {
const Component = { template: '<br />' }
const slot = () => {} const slot = () => {}
expect( expect(
h('div', null, { h(Component, null, {
foo: slot foo: slot
}) })
).toMatchObject( ).toMatchObject(
createVNode('div', null, { createVNode(Component, null, {
foo: slot foo: slot
}) })
) )

View File

@ -4,7 +4,8 @@ import {
createVNode, createVNode,
VNodeChildren, VNodeChildren,
Fragment, Fragment,
Portal Portal,
isVNode
} from './vnode' } from './vnode'
import { isObject, isArray } from '@vue/shared' import { isObject, isArray } from '@vue/shared'
import { Ref } from '@vue/reactivity' import { Ref } from '@vue/reactivity'
@ -34,17 +35,19 @@ h('div', {})
// type + omit props + children // type + omit props + children
// Omit props does NOT support named slots // Omit props does NOT support named slots
h('div', []) // array h('div', []) // array
h('div', () => {}) // default slot
h('div', 'foo') // text h('div', 'foo') // text
h('div', h('br')) // vnode
h(Component, () => {}) // default slot
// type + props + children // type + props + children
h('div', {}, []) // array h('div', {}, []) // array
h('div', {}, () => {}) // default slot
h('div', {}, {}) // named slots
h('div', {}, 'foo') // text 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 // named slots without props requires explicit `null` to avoid ambiguity
h('div', null, {}) h(Component, null, {})
**/ **/
export interface RawProps { export interface RawProps {
@ -61,6 +64,7 @@ export type RawChildren =
| string | string
| number | number
| boolean | boolean
| VNode
| VNodeChildren | VNodeChildren
| (() => any) | (() => any)
@ -142,6 +146,10 @@ export function h(
): VNode { ): VNode {
if (arguments.length === 2) { if (arguments.length === 2) {
if (isObject(propsOrChildren) && !isArray(propsOrChildren)) { if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
// single vnode without props
if (isVNode(propsOrChildren)) {
return createVNode(type, null, [propsOrChildren])
}
// props without children // props without children
return createVNode(type, propsOrChildren) return createVNode(type, propsOrChildren)
} else { } else {
@ -149,6 +157,9 @@ export function h(
return createVNode(type, null, propsOrChildren) return createVNode(type, null, propsOrChildren)
} }
} else { } else {
if (isVNode(children)) {
children = [children]
}
return createVNode(type, propsOrChildren, children) return createVNode(type, propsOrChildren, children)
} }
} }

View File

@ -129,7 +129,7 @@ export function createBlock(
return vnode return vnode
} }
export function isVNode(value: any): boolean { export function isVNode(value: any): value is VNode {
return value ? value._isVNode === true : false return value ? value._isVNode === true : false
} }