From 11214eedd2699e15106c44927f4d1206b111fbd3 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 10 Nov 2022 15:08:25 +0800 Subject: [PATCH] fix(teleport/css-v-bind): fix css v-bind in teleport in child component slot --- .../runtime-core/src/components/Teleport.ts | 17 ++++++------- packages/runtime-core/src/vnode.ts | 11 +++++++-- .../__tests__/helpers/useCssVars.spec.ts | 24 +++++++++++++++++++ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/packages/runtime-core/src/components/Teleport.ts b/packages/runtime-core/src/components/Teleport.ts index 18c4aee86a0..f9f845298dc 100644 --- a/packages/runtime-core/src/components/Teleport.ts +++ b/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() } } diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 2122f9f855a..7d8017e650a 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/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( 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) diff --git a/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts b/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts index e9dd3659650..7d24ec0f434 100644 --- a/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts +++ b/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' })