diff --git a/packages/runtime-core/__tests__/components/Teleport.spec.ts b/packages/runtime-core/__tests__/components/Teleport.spec.ts index f6babd9263b..8b234e2b1e6 100644 --- a/packages/runtime-core/__tests__/components/Teleport.spec.ts +++ b/packages/runtime-core/__tests__/components/Teleport.spec.ts @@ -8,7 +8,9 @@ import { ref, nextTick, markRaw, - defineComponent + defineComponent, + withDirectives, + createApp } from '@vue/runtime-test' import { createVNode, Fragment } from '../../src/vnode' import { compile, render as domRender } from 'vue' @@ -432,4 +434,42 @@ describe('renderer: teleport', () => { `"
teleported
false"` ) }) + + // #3497 + test(`the dir hooks of the Teleport's children should be called correctly`, async () => { + const target = nodeOps.createElement('div') + const root = nodeOps.createElement('div') + const toggle = ref(true) + const dir = { + mounted: jest.fn(), + unmounted: jest.fn() + } + + const app = createApp({ + setup() { + return () => { + return toggle.value + ? h(Teleport, { to: target }, [ + withDirectives(h('div', ['foo']), [[dir]]) + ]) + : null + } + } + }) + app.mount(root) + + expect(serializeInner(root)).toMatchInlineSnapshot( + `""` + ) + expect(serializeInner(target)).toMatchInlineSnapshot(`"
foo
"`) + expect(dir.mounted).toHaveBeenCalledTimes(1) + expect(dir.unmounted).toHaveBeenCalledTimes(0) + + toggle.value = false + await nextTick() + expect(serializeInner(root)).toMatchInlineSnapshot(`""`) + expect(serializeInner(target)).toMatchInlineSnapshot(`""`) + expect(dir.mounted).toHaveBeenCalledTimes(1) + expect(dir.unmounted).toHaveBeenCalledTimes(1) + }) }) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 4375dcdbf10..5122e7a9131 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -2096,7 +2096,16 @@ function baseCreateRenderer( invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount') } - if ( + if (shapeFlag & ShapeFlags.TELEPORT) { + ;(vnode.type as typeof TeleportImpl).remove( + vnode, + parentComponent, + parentSuspense, + optimized, + internals, + doRemove + ) + } else if ( dynamicChildren && // #1153: fast path should not be taken for non-stable (v-for) fragments (type !== Fragment || @@ -2119,17 +2128,6 @@ function baseCreateRenderer( unmountChildren(children as VNode[], parentComponent, parentSuspense) } - if (shapeFlag & ShapeFlags.TELEPORT) { - ;(vnode.type as typeof TeleportImpl).remove( - vnode, - parentComponent, - parentSuspense, - optimized, - internals, - doRemove - ) - } - if (doRemove) { remove(vnode) }