From 04a4ebaaeb4418d211293fc7b92c19c42a425cbd Mon Sep 17 00:00:00 2001 From: underfin <2218301630@qq.com> Date: Tue, 28 Jul 2020 23:23:39 +0800 Subject: [PATCH] fix(runtime-core): use correct container for moving `Teleport` content (#1703) --- .../__tests__/components/Teleport.spec.ts | 49 ++++++++++++++++++- .../runtime-core/src/components/Teleport.ts | 7 +++ packages/runtime-core/src/renderer.ts | 3 +- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/__tests__/components/Teleport.spec.ts b/packages/runtime-core/__tests__/components/Teleport.spec.ts index 99bea073072..eaa6e227ee3 100644 --- a/packages/runtime-core/__tests__/components/Teleport.spec.ts +++ b/packages/runtime-core/__tests__/components/Teleport.spec.ts @@ -6,9 +6,11 @@ import { Teleport, Text, ref, - nextTick + nextTick, + markRaw } from '@vue/runtime-test' import { createVNode, Fragment } from '../../src/vnode' +import { compile } from 'vue' describe('renderer: teleport', () => { test('should work', () => { @@ -299,4 +301,49 @@ describe('renderer: teleport', () => { ) expect(serializeInner(target)).toBe('') }) + + test('should work with block tree', async () => { + const target = nodeOps.createElement('div') + const root = nodeOps.createElement('div') + const disabled = ref(false) + + const App = { + setup() { + return { + target: markRaw(target), + disabled + } + }, + render: compile(` + +
teleported
{{ disabled }} +
+
root
+ `) + } + render(h(App), root) + expect(serializeInner(root)).toMatchInlineSnapshot( + `"
root
"` + ) + expect(serializeInner(target)).toMatchInlineSnapshot( + `"
teleported
false"` + ) + + disabled.value = true + await nextTick() + expect(serializeInner(root)).toMatchInlineSnapshot( + `"
teleported
true
root
"` + ) + expect(serializeInner(target)).toBe(``) + + // toggle back + disabled.value = false + await nextTick() + expect(serializeInner(root)).toMatchInlineSnapshot( + `"
root
"` + ) + expect(serializeInner(target)).toMatchInlineSnapshot( + `"
teleported
false"` + ) + }) }) diff --git a/packages/runtime-core/src/components/Teleport.ts b/packages/runtime-core/src/components/Teleport.ts index a4fdd4b505f..8c588df128b 100644 --- a/packages/runtime-core/src/components/Teleport.ts +++ b/packages/runtime-core/src/components/Teleport.ts @@ -139,6 +139,13 @@ export const TeleportImpl = { parentSuspense, isSVG ) + if (n2.patchFlag > 0 && n2.shapeFlag & ShapeFlags.ARRAY_CHILDREN) { + const oldChildren = n1.children as VNode[] + const children = n2.children as VNode[] + for (let i = 0; i < children.length; i++) { + children[i].el = oldChildren[i].el + } + } } else if (!optimized) { patchChildren( n1, diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 09f2ab242b4..df26f87ac71 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -960,7 +960,8 @@ function baseCreateRenderer( // which also requires the correct parent container !isSameVNodeType(oldVNode, newVNode) || // - In the case of a component, it could contain anything. - oldVNode.shapeFlag & ShapeFlags.COMPONENT + oldVNode.shapeFlag & ShapeFlags.COMPONENT || + oldVNode.shapeFlag & ShapeFlags.TELEPORT ? hostParentNode(oldVNode.el!)! : // In other cases, the parent container is not actually used so we // just pass the block element here to avoid a DOM parentNode call.