]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(teleport): handle css var update on nested fragment (#14284)
authorJack <50577157+jackma9604@users.noreply.github.com>
Thu, 8 Jan 2026 08:43:47 +0000 (16:43 +0800)
committerGitHub <noreply@github.com>
Thu, 8 Jan 2026 08:43:47 +0000 (16:43 +0800)
Co-authored-by: daiwei <daiwei521@126.com>
packages/runtime-vapor/__tests__/helpers/useCssVars.spec.ts
packages/runtime-vapor/src/components/Teleport.ts

index 6ea2d87c2bf3bcfc71257038012f20390a5811ae..ea8ce0a2b578d9a0f6a6b25a842761e5e39349b2 100644 (file)
@@ -297,6 +297,68 @@ describe('useVaporCssVars', () => {
     expect(host.children[0].outerHTML.includes('data-v-owner')).toBe(true)
   })
 
+  test('with teleport and nested component', async () => {
+    const state = reactive({ color: 'red' })
+    const target = document.createElement('div')
+    document.body.appendChild(target)
+
+    const value = ref(true)
+    const Child = defineVaporComponent({
+      setup(_, { slots }) {
+        return slots.default!()
+      },
+    })
+
+    const Comp = defineVaporComponent({
+      setup() {
+        return createComponent(Child, null, {
+          default: () => {
+            return createComponent(Child, null, {
+              default: () => {
+                return createIf(
+                  () => value.value,
+                  () => {
+                    return template('<div></div>')()
+                  },
+                  () => {
+                    return template('<span></span>')()
+                  },
+                )
+              },
+            })
+          },
+        })
+      },
+    })
+
+    define({
+      setup() {
+        useVaporCssVars(() => state)
+        const n1 = createComponent(
+          VaporTeleport,
+          { to: () => target },
+          {
+            default: () => createComponent(Comp),
+          },
+        )
+        return n1
+      },
+    }).render()
+
+    await nextTick()
+    let el = target.children[0] as HTMLElement
+    expect(el.tagName).toBe('DIV')
+    expect(el.outerHTML.includes('data-v-owner')).toBe(true)
+    expect(el.style.getPropertyValue(`--color`)).toBe('red')
+
+    value.value = false
+    await nextTick()
+    el = target.children[0] as HTMLElement
+    expect(el.tagName).toBe('SPAN')
+    expect(el.outerHTML.includes('data-v-owner')).toBe(true)
+    expect(el.style.getPropertyValue(`--color`)).toBe('red')
+  })
+
   test('with string style', async () => {
     const state = reactive({ color: 'red' })
     const root = document.createElement('div')
index 1fadf8ffc20eabdaba51aa8b7c9b63fc32c156f0..0e5b26ca1726e17611709e10f07b55ada11c8a4a 100644 (file)
@@ -107,24 +107,12 @@ export class TeleportFragment extends VaporFragment {
         this.rawSlots!.default && (this.rawSlots!.default as BlockFn)(),
       )
     })
-
     const nodes = this.nodes
-    // register updateCssVars to root fragments's update hooks so that
+
+    // register updateCssVars to nested fragments's update hooks so that
     // it will be called when root fragment changed
     if (this.parentComponent && this.parentComponent.ut) {
-      if (isFragment(nodes)) {
-        ;(nodes.onUpdated || (nodes.onUpdated = [])).push(() =>
-          updateCssVars(this),
-        )
-      } else if (isArray(nodes)) {
-        nodes.forEach(node => {
-          if (isFragment(node)) {
-            ;(node.onUpdated || (node.onUpdated = [])).push(() =>
-              updateCssVars(this),
-            )
-          }
-        })
-      }
+      this.registerUpdateCssVars(nodes)
     }
 
     if (__DEV__) {
@@ -138,6 +126,19 @@ export class TeleportFragment extends VaporFragment {
     }
   }
 
+  private registerUpdateCssVars(block: Block) {
+    if (isFragment(block)) {
+      ;(block.onUpdated || (block.onUpdated = [])).push(() =>
+        updateCssVars(this),
+      )
+      this.registerUpdateCssVars(block.nodes)
+    } else if (isVaporComponent(block)) {
+      this.registerUpdateCssVars(block.block)
+    } else if (isArray(block)) {
+      block.forEach(node => this.registerUpdateCssVars(node))
+    }
+  }
+
   private handleChildrenUpdate(children: Block): void {
     // not mounted yet
     if (!this.parent || isHydrating) {