Просмотр исходного кода

fix(teleport): clean up old anchors when teleport target changes (#14588)

edison 3 месяцев назад
Родитель
Сommit
d614897b5c

+ 31 - 0
packages/runtime-vapor/__tests__/components/Teleport.spec.ts

@@ -1380,3 +1380,34 @@ function runSharedTests(deferMode: boolean): void {
     expect(beforeEnter).toHaveBeenCalledTimes(0)
   })
 }
+
+test('should clean up old anchors when target changes', async () => {
+  const targetA = document.createElement('div')
+  const targetB = document.createElement('div')
+  const target = ref(targetA)
+
+  const { mount } = define({
+    setup() {
+      const n0 = createComponent(
+        VaporTeleport,
+        { to: () => target.value },
+        { default: () => template('<div>teleported</div>')() },
+      )
+      return n0
+    },
+  }).create()
+  const root = document.createElement('div')
+  mount(root)
+  await nextTick()
+
+  const oldChildCount = targetA.childNodes.length
+  expect(oldChildCount).toBeGreaterThan(0) // has targetStart + content + targetAnchor
+
+  target.value = targetB
+  await nextTick()
+
+  // Old target should have no residual anchor nodes
+  expect(targetA.childNodes.length).toBe(0)
+  // New target should have the content
+  expect(targetB.childNodes.length).toBe(oldChildCount)
+})

+ 7 - 0
packages/runtime-vapor/src/components/Teleport.ts

@@ -199,6 +199,13 @@ export class TeleportFragment extends VaporFragment {
         // target changed
         this.targetAnchor.parentNode !== target
       ) {
+        // clean up old anchors from previous target when target changes
+        if (this.targetStart) {
+          remove(this.targetStart, this.targetStart.parentNode!)
+        }
+        if (this.targetAnchor) {
+          remove(this.targetAnchor, this.targetAnchor.parentNode!)
+        }
         insert((this.targetStart = createTextNode('')), target)
         insert((this.targetAnchor = createTextNode('')), target)
       }