From eaee781598bc78f3c6fbd25b752db9d3ba31e75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=B6=E8=BF=9C=E6=96=B9?= Date: Tue, 5 Sep 2023 17:51:47 +0800 Subject: [PATCH 1/3] fix(runtime-dom): fix `anchor` loss caused by `unmount` --- packages/runtime-dom/src/nodeOps.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/runtime-dom/src/nodeOps.ts b/packages/runtime-dom/src/nodeOps.ts index daf56fc6f3a..284f8ad7e83 100644 --- a/packages/runtime-dom/src/nodeOps.ts +++ b/packages/runtime-dom/src/nodeOps.ts @@ -8,7 +8,11 @@ const templateContainer = doc && /*#__PURE__*/ doc.createElement('template') export const nodeOps: Omit, 'patchProp'> = { insert: (child, parent, anchor) => { - parent.insertBefore(child, anchor || null) + if (anchor?.parentNode === parent) { + parent.insertBefore(child, anchor || null) + } else { + parent.appendChild(child) + } }, remove: child => { From 3a4514b4d16f7aa7c25989d04214cc880321d746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=B6=E8=BF=9C=E6=96=B9?= Date: Wed, 6 Sep 2023 12:02:33 +0800 Subject: [PATCH 2/3] test(Teleport): add test case --- .../__tests__/components/Teleport.spec.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/packages/runtime-core/__tests__/components/Teleport.spec.ts b/packages/runtime-core/__tests__/components/Teleport.spec.ts index 7371f53f7b6..c56a0be376b 100644 --- a/packages/runtime-core/__tests__/components/Teleport.spec.ts +++ b/packages/runtime-core/__tests__/components/Teleport.spec.ts @@ -528,4 +528,44 @@ describe('renderer: teleport', () => { `"
teleported
"` ) }) + + // #9071 + test('should render within the target element unique child element', async () => { + const root = document.createElement('div') + + const show = ref(false) + + const App = defineComponent({ + setup() { + return () => { + return show.value + ? h(Teleport, { to: root }, h('div', 'Teleported')) + : h('div', 'foo') + } + } + }) + + domRender(h(App), root) + + expect(root.innerHTML).toMatchInlineSnapshot('"
foo
"') + + show.value = true + await nextTick() + + expect(root.innerHTML).toMatchInlineSnapshot( + '"
Teleported
"' + ) + + show.value = false + await nextTick() + + expect(root.innerHTML).toMatchInlineSnapshot('"
foo
"') + + show.value = true + await nextTick() + + expect(root.innerHTML).toMatchInlineSnapshot( + '"
Teleported
"' + ) + }) }) From 42b1375065591162879e97913d07dc353481af56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=B6=E8=BF=9C=E6=96=B9?= Date: Wed, 6 Sep 2023 13:30:40 +0800 Subject: [PATCH 3/3] chore(runtime-dom): replace optional chaining syntax --- packages/runtime-dom/src/nodeOps.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/runtime-dom/src/nodeOps.ts b/packages/runtime-dom/src/nodeOps.ts index 284f8ad7e83..a0fa47158fd 100644 --- a/packages/runtime-dom/src/nodeOps.ts +++ b/packages/runtime-dom/src/nodeOps.ts @@ -8,11 +8,9 @@ const templateContainer = doc && /*#__PURE__*/ doc.createElement('template') export const nodeOps: Omit, 'patchProp'> = { insert: (child, parent, anchor) => { - if (anchor?.parentNode === parent) { - parent.insertBefore(child, anchor || null) - } else { - parent.appendChild(child) - } + // #9071 + anchor = anchor && anchor.parentNode === parent ? anchor : null + parent.insertBefore(child, anchor) }, remove: child => {