Quellcode durchsuchen

fix(teleport/css-v-bind): fix css v-bind in teleport in child component slot

Evan You vor 3 Jahren
Ursprung
Commit
11214eedd2

+ 7 - 10
packages/runtime-core/src/components/Teleport.ts

@@ -223,7 +223,7 @@ export const TeleportImpl = {
       }
     }
 
-    updateCssVars(parentComponent, n2)
+    updateCssVars(n2)
   },
 
   remove(
@@ -385,7 +385,7 @@ function hydrateTeleport(
         )
       }
     }
-    updateCssVars(parentComponent, vnode)
+    updateCssVars(vnode)
   }
   return vnode.anchor && nextSibling(vnode.anchor as Node)
 }
@@ -396,19 +396,16 @@ export const Teleport = TeleportImpl as unknown as {
   new (): { $props: VNodeProps & TeleportProps }
 }
 
-function updateCssVars(
-  parentComponent: ComponentInternalInstance | null,
-  vnode: VNode
-) {
+function updateCssVars(vnode: VNode) {
   // presence of .ut method indicates owner component uses css vars.
   // code path here can assume browser environment.
-  if (parentComponent && parentComponent.ut) {
+  const ctx = vnode.ctx
+  if (ctx && ctx.ut) {
     let node = (vnode.children as VNode[])[0].el!
     while (node !== vnode.targetAnchor) {
-      if (node.nodeType === 1)
-        node.setAttribute('data-v-owner', parentComponent.uid)
+      if (node.nodeType === 1) node.setAttribute('data-v-owner', ctx.uid)
       node = node.nextSibling
     }
-    parentComponent.ut()
+    ctx.ut()
   }
 }

+ 9 - 2
packages/runtime-core/src/vnode.ts

@@ -205,6 +205,11 @@ export interface VNode<
   // application root node only
   appContext: AppContext | null
 
+  /**
+   * @internal lexical scope owner instance
+   */
+  ctx: ComponentInternalInstance | null
+
   /**
    * @internal attached by v-memo
    */
@@ -439,7 +444,8 @@ function createBaseVNode(
     patchFlag,
     dynamicProps,
     dynamicChildren: null,
-    appContext: null
+    appContext: null,
+    ctx: currentRenderingInstance
   } as VNode
 
   if (needFullChildrenNormalization) {
@@ -661,7 +667,8 @@ export function cloneVNode<T, U>(
     ssContent: vnode.ssContent && cloneVNode(vnode.ssContent),
     ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback),
     el: vnode.el,
-    anchor: vnode.anchor
+    anchor: vnode.anchor,
+    ctx: vnode.ctx
   }
   if (__COMPAT__) {
     defineLegacyVNodeProperties(cloned as VNode)

+ 24 - 0
packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts

@@ -218,6 +218,30 @@ describe('useCssVars', () => {
     }
   })
 
+  test('with teleport in child slot', async () => {
+    document.body.innerHTML = ''
+    const state = reactive({ color: 'red' })
+    const root = document.createElement('div')
+    const target = document.body
+
+    const Child: FunctionalComponent = (_, { slots }) => {
+      return h('div', slots.default && slots.default())
+    }
+
+    const App = {
+      setup() {
+        useCssVars(() => state)
+        return () => h(Child, () => [h(Teleport, { to: target }, [h('div')])])
+      }
+    }
+
+    render(h(App), root)
+    await nextTick()
+    for (const c of [].slice.call(target.children as any)) {
+      expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
+    }
+  })
+
   test('with teleport(change subTree)', async () => {
     document.body.innerHTML = ''
     const state = reactive({ color: 'red' })