Skip to content

Commit 04a4eba

Browse files
authored
fix(runtime-core): use correct container for moving Teleport content (#1703)
1 parent fbf865d commit 04a4eba

File tree

3 files changed

+57
-2
lines changed

3 files changed

+57
-2
lines changed

packages/runtime-core/__tests__/components/Teleport.spec.ts

+48-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import {
66
Teleport,
77
Text,
88
ref,
9-
nextTick
9+
nextTick,
10+
markRaw
1011
} from '@vue/runtime-test'
1112
import { createVNode, Fragment } from '../../src/vnode'
13+
import { compile } from 'vue'
1214

1315
describe('renderer: teleport', () => {
1416
test('should work', () => {
@@ -299,4 +301,49 @@ describe('renderer: teleport', () => {
299301
)
300302
expect(serializeInner(target)).toBe('')
301303
})
304+
305+
test('should work with block tree', async () => {
306+
const target = nodeOps.createElement('div')
307+
const root = nodeOps.createElement('div')
308+
const disabled = ref(false)
309+
310+
const App = {
311+
setup() {
312+
return {
313+
target: markRaw(target),
314+
disabled
315+
}
316+
},
317+
render: compile(`
318+
<teleport :to="target" :disabled="disabled">
319+
<div>teleported</div><span>{{ disabled }}</span>
320+
</teleport>
321+
<div>root</div>
322+
`)
323+
}
324+
render(h(App), root)
325+
expect(serializeInner(root)).toMatchInlineSnapshot(
326+
`"<!--teleport start--><!--teleport end--><div>root</div>"`
327+
)
328+
expect(serializeInner(target)).toMatchInlineSnapshot(
329+
`"<div>teleported</div><span>false</span>"`
330+
)
331+
332+
disabled.value = true
333+
await nextTick()
334+
expect(serializeInner(root)).toMatchInlineSnapshot(
335+
`"<!--teleport start--><div>teleported</div><span>true</span><!--teleport end--><div>root</div>"`
336+
)
337+
expect(serializeInner(target)).toBe(``)
338+
339+
// toggle back
340+
disabled.value = false
341+
await nextTick()
342+
expect(serializeInner(root)).toMatchInlineSnapshot(
343+
`"<!--teleport start--><!--teleport end--><div>root</div>"`
344+
)
345+
expect(serializeInner(target)).toMatchInlineSnapshot(
346+
`"<div>teleported</div><span>false</span>"`
347+
)
348+
})
302349
})

packages/runtime-core/src/components/Teleport.ts

+7
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ export const TeleportImpl = {
139139
parentSuspense,
140140
isSVG
141141
)
142+
if (n2.patchFlag > 0 && n2.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
143+
const oldChildren = n1.children as VNode[]
144+
const children = n2.children as VNode[]
145+
for (let i = 0; i < children.length; i++) {
146+
children[i].el = oldChildren[i].el
147+
}
148+
}
142149
} else if (!optimized) {
143150
patchChildren(
144151
n1,

packages/runtime-core/src/renderer.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,8 @@ function baseCreateRenderer(
960960
// which also requires the correct parent container
961961
!isSameVNodeType(oldVNode, newVNode) ||
962962
// - In the case of a component, it could contain anything.
963-
oldVNode.shapeFlag & ShapeFlags.COMPONENT
963+
oldVNode.shapeFlag & ShapeFlags.COMPONENT ||
964+
oldVNode.shapeFlag & ShapeFlags.TELEPORT
964965
? hostParentNode(oldVNode.el!)!
965966
: // In other cases, the parent container is not actually used so we
966967
// just pass the block element here to avoid a DOM parentNode call.

0 commit comments

Comments
 (0)