mirror of https://github.com/vuejs/core.git
feat(runtime-core): add unwrapFragment to flatten nested Fragment nodes in vnode arrays
This commit is contained in:
parent
ba391f5fdf
commit
582f16accf
|
@ -0,0 +1,48 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import { Fragment, type VNode, h, unwrapFragment } from '../src/index'
|
||||
|
||||
describe('unwrapFragment', () => {
|
||||
it('returns empty array if input is undefined or empty', () => {
|
||||
expect(unwrapFragment(undefined)).toEqual([])
|
||||
expect(unwrapFragment([])).toEqual([])
|
||||
})
|
||||
|
||||
it('returns same array if no Fragment present', () => {
|
||||
const vnode1 = h('div')
|
||||
const vnode2 = h('span')
|
||||
const input = [vnode1, vnode2]
|
||||
const result = unwrapFragment(input)
|
||||
expect(result).toEqual(input)
|
||||
})
|
||||
|
||||
it('unwraps single level Fragment', () => {
|
||||
const children = [h('div', 'a'), h('div', 'b')]
|
||||
const fragmentVNode: VNode = h(Fragment, null, children)
|
||||
const input = [fragmentVNode]
|
||||
const result = unwrapFragment(input)
|
||||
expect(result).toHaveLength(2)
|
||||
expect(result).toEqual(children)
|
||||
})
|
||||
|
||||
it('unwraps nested Fragments recursively', () => {
|
||||
const innerChildren = [h('span', 'x'), h('span', 'y')]
|
||||
const innerFragment = h(Fragment, null, innerChildren)
|
||||
const outerChildren = [innerFragment, h('div', 'z')]
|
||||
const outerFragment = h(Fragment, null, outerChildren)
|
||||
const input = [outerFragment]
|
||||
const result = unwrapFragment(input)
|
||||
// Should flatten all fragments recursively
|
||||
expect(result).toHaveLength(3)
|
||||
expect(result).toEqual([...innerChildren, outerChildren[1]])
|
||||
})
|
||||
|
||||
it('unwraps mixed array with Fragment and non-Fragment vnode', () => {
|
||||
const children = [h('li', 'item1'), h('li', 'item2')]
|
||||
const fragmentVNode = h(Fragment, null, children)
|
||||
const nonFragmentVNode = h('p', 'paragraph')
|
||||
const input = [fragmentVNode, nonFragmentVNode]
|
||||
const result = unwrapFragment(input)
|
||||
expect(result).toHaveLength(3)
|
||||
expect(result).toEqual([...children, nonFragmentVNode])
|
||||
})
|
||||
})
|
|
@ -125,6 +125,8 @@ export { withDirectives } from './directives'
|
|||
// SSR context
|
||||
export { useSSRContext, ssrContextKey } from './helpers/useSsrContext'
|
||||
|
||||
export { unwrapFragment } from './unwrapFragment'
|
||||
|
||||
// Custom Renderer API ---------------------------------------------------------
|
||||
|
||||
export { createRenderer, createHydrationRenderer } from './renderer'
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { type VNode, isFragmentVNode } from './vnode'
|
||||
|
||||
/**
|
||||
* 展开 vnode 数组中所有 Fragment 节点,将它们的子节点平铺出来。
|
||||
*/
|
||||
export const unwrapFragment = (vnodes: VNode[] | undefined): VNode[] => {
|
||||
if (!vnodes) return []
|
||||
const result: VNode[] = []
|
||||
for (const vnode of vnodes) {
|
||||
if (isFragmentVNode(vnode)) {
|
||||
result.push(...unwrapFragment(vnode.children as VNode[]))
|
||||
} else {
|
||||
result.push(vnode)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
|
@ -387,6 +387,10 @@ export function isVNode(value: any): value is VNode {
|
|||
return value ? value.__v_isVNode === true : false
|
||||
}
|
||||
|
||||
export function isFragmentVNode(vnode: VNode): vnode is VNode {
|
||||
return !!vnode && vnode.type === Fragment
|
||||
}
|
||||
|
||||
export function isSameVNodeType(n1: VNode, n2: VNode): boolean {
|
||||
if (__DEV__ && n2.shapeFlag & ShapeFlags.COMPONENT && n1.component) {
|
||||
const dirtyInstances = hmrDirtyComponents.get(n2.type as ConcreteComponent)
|
||||
|
|
Loading…
Reference in New Issue