fix(portal): portal should always remove its children when unmounted
This commit is contained in:
parent
cb31eb4d0a
commit
16cd8eee78
@ -26,7 +26,8 @@ import {
|
|||||||
CREATE_BLOCK,
|
CREATE_BLOCK,
|
||||||
FRAGMENT,
|
FRAGMENT,
|
||||||
CREATE_COMMENT,
|
CREATE_COMMENT,
|
||||||
OPEN_BLOCK
|
OPEN_BLOCK,
|
||||||
|
PORTAL
|
||||||
} from '../runtimeHelpers'
|
} from '../runtimeHelpers'
|
||||||
import { injectProp } from '../utils'
|
import { injectProp } from '../utils'
|
||||||
import { PatchFlags, PatchFlagNames } from '@vue/shared'
|
import { PatchFlags, PatchFlagNames } from '@vue/shared'
|
||||||
@ -216,7 +217,9 @@ function createChildrenCodegenNode(
|
|||||||
vnodeCall.type === NodeTypes.VNODE_CALL &&
|
vnodeCall.type === NodeTypes.VNODE_CALL &&
|
||||||
// component vnodes are always tracked and its children are
|
// component vnodes are always tracked and its children are
|
||||||
// compiled into slots so no need to make it a block
|
// compiled into slots so no need to make it a block
|
||||||
(firstChild as ElementNode).tagType !== ElementTypes.COMPONENT
|
((firstChild as ElementNode).tagType !== ElementTypes.COMPONENT ||
|
||||||
|
// portal has component type but isn't always tracked
|
||||||
|
vnodeCall.tag === PORTAL)
|
||||||
) {
|
) {
|
||||||
vnodeCall.isBlock = true
|
vnodeCall.isBlock = true
|
||||||
helper(OPEN_BLOCK)
|
helper(OPEN_BLOCK)
|
||||||
|
@ -76,4 +76,21 @@ describe('renderer: portal', () => {
|
|||||||
|
|
||||||
expect(serializeInner(target)).toMatchSnapshot()
|
expect(serializeInner(target)).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should remove children when unmounted', () => {
|
||||||
|
const target = nodeOps.createElement('div')
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
|
||||||
|
const Comp = defineComponent(() => () => [
|
||||||
|
h(Portal, { target }, h('div', 'teleported')),
|
||||||
|
h('div', 'root')
|
||||||
|
])
|
||||||
|
render(h(Comp), root)
|
||||||
|
expect(serializeInner(target)).toMatchInlineSnapshot(
|
||||||
|
`"<div>teleported</div>"`
|
||||||
|
)
|
||||||
|
|
||||||
|
render(null, root)
|
||||||
|
expect(serializeInner(target)).toBe('')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`renderer: portal should remove children when unmounted 1`] = `"<div>teleported</div>"`;
|
||||||
|
|
||||||
exports[`renderer: portal should update children 1`] = `"<div>teleported</div>"`;
|
exports[`renderer: portal should update children 1`] = `"<div>teleported</div>"`;
|
||||||
|
|
||||||
exports[`renderer: portal should update children 2`] = `""`;
|
exports[`renderer: portal should update children 2`] = `""`;
|
||||||
|
@ -113,6 +113,20 @@ export const PortalImpl = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
remove(
|
||||||
|
vnode: VNode,
|
||||||
|
{ r: remove, o: { setElementText } }: RendererInternals
|
||||||
|
) {
|
||||||
|
const { target, shapeFlag, children } = vnode
|
||||||
|
if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
|
||||||
|
setElementText(target!, '')
|
||||||
|
} else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
|
||||||
|
for (let i = 0; i < (children as VNode[]).length; i++) {
|
||||||
|
remove((children as VNode[])[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ export interface RendererInternals<
|
|||||||
> {
|
> {
|
||||||
p: PatchFn
|
p: PatchFn
|
||||||
um: UnmountFn
|
um: UnmountFn
|
||||||
|
r: RemoveFn
|
||||||
m: MoveFn
|
m: MoveFn
|
||||||
mt: MountComponentFn
|
mt: MountComponentFn
|
||||||
mc: MountChildrenFn
|
mc: MountChildrenFn
|
||||||
@ -210,6 +211,8 @@ type UnmountFn = (
|
|||||||
doRemove?: boolean
|
doRemove?: boolean
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
|
type RemoveFn = (vnode: VNode) => void
|
||||||
|
|
||||||
type UnmountChildrenFn = (
|
type UnmountChildrenFn = (
|
||||||
children: VNode[],
|
children: VNode[],
|
||||||
parentComponent: ComponentInternalInstance | null,
|
parentComponent: ComponentInternalInstance | null,
|
||||||
@ -1688,6 +1691,11 @@ function baseCreateRenderer(
|
|||||||
unmountChildren(children as VNode[], parentComponent, parentSuspense)
|
unmountChildren(children as VNode[], parentComponent, parentSuspense)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// an unmounted portal should always remove its children
|
||||||
|
if (shapeFlag & ShapeFlags.PORTAL) {
|
||||||
|
;(vnode.type as typeof PortalImpl).remove(vnode, internals)
|
||||||
|
}
|
||||||
|
|
||||||
if (doRemove) {
|
if (doRemove) {
|
||||||
remove(vnode)
|
remove(vnode)
|
||||||
}
|
}
|
||||||
@ -1702,7 +1710,7 @@ function baseCreateRenderer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const remove = (vnode: VNode) => {
|
const remove: RemoveFn = vnode => {
|
||||||
const { type, el, anchor, transition } = vnode
|
const { type, el, anchor, transition } = vnode
|
||||||
if (type === Fragment) {
|
if (type === Fragment) {
|
||||||
removeFragment(el!, anchor!)
|
removeFragment(el!, anchor!)
|
||||||
@ -1888,6 +1896,7 @@ function baseCreateRenderer(
|
|||||||
p: patch,
|
p: patch,
|
||||||
um: unmount,
|
um: unmount,
|
||||||
m: move,
|
m: move,
|
||||||
|
r: remove,
|
||||||
mt: mountComponent,
|
mt: mountComponent,
|
||||||
mc: mountChildren,
|
mc: mountChildren,
|
||||||
pc: patchChildren,
|
pc: patchChildren,
|
||||||
|
Loading…
Reference in New Issue
Block a user