diff --git a/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts b/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts index d35f5bb1a6c..d9c4701678e 100644 --- a/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts +++ b/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts @@ -16,7 +16,8 @@ import { createElementBlock, createCommentVNode, createVNode, - Transition + Transition, + createBlock } from '@vue/runtime-dom' describe('useCssVars', () => { @@ -309,8 +310,7 @@ describe('useCssVars', () => { createElementBlock( 'div', { - key: 0, - class: 'text' + key: 0 }, ' test ' )) @@ -360,8 +360,7 @@ describe('useCssVars', () => { createElementBlock( 'div', { - key: 0, - class: 'text' + key: 0 }, 'test' )) @@ -390,4 +389,70 @@ describe('useCssVars', () => { expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red') } }) + + test('with teleport(transition & v-if element)', async () => { + document.body.innerHTML = '' + const state = reactive({ color: 'red' }) + const root = document.createElement('div') + const target = document.body + const toggle = ref(true) + + const App = { + setup() { + useCssVars(() => state) + return () => [ + (openBlock(), + createBlock(Teleport, { to: target }, [ + createVNode( + Transition, + {}, + { + default: withCtx(() => [ + toggle.value + ? (openBlock(), + createElementBlock( + 'div', + { + key: 0 + }, + 'test' + )) + : createCommentVNode('v-if', true) + ]), + _: 1 /* STABLE */ + } + ) + ])), + (openBlock(), + createBlock(Teleport, { to: target }, [ + toggle.value + ? (openBlock(), + createElementBlock( + 'div', + { + key: 0 + }, + 'element' + )) + : createCommentVNode('v-if', true) + ])) + ] + } + } + + render(h(App), root) + await nextTick() + expect(target.children.length).toBe(2) + for (const c of [].slice.call(target.children as any)) { + expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red') + } + toggle.value = false + await nextTick() + toggle.value = true + await nextTick() + expect(target.children.length).toBe(2) + for (const c of [].slice.call(target.children as any)) { + expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red') + } + }) }) diff --git a/packages/runtime-dom/src/helpers/useCssVars.ts b/packages/runtime-dom/src/helpers/useCssVars.ts index 7db080b5c0b..1fe38438331 100644 --- a/packages/runtime-dom/src/helpers/useCssVars.ts +++ b/packages/runtime-dom/src/helpers/useCssVars.ts @@ -9,7 +9,8 @@ import { onUnmounted, resolveTarget, TeleportProps, - updateCssVars + updateCssVars, + onUpdated } from '@vue/runtime-core' import { ShapeFlags, isArray } from '@vue/shared' import { nodeOps } from '../nodeOps' @@ -46,21 +47,28 @@ export function useCssVars(getter: (ctx: any) => Record) { onMounted(() => { const obs = [onSubTreeChange(instance.subTree.el!.parentNode, setVars)] - const observeTeleportTarget = (vnode: VNode) => { + const observeTeleportTarget = (vnode: VNode, init = true) => { if (vnode.shapeFlag & ShapeFlags.TELEPORT) { const target = resolveTarget( vnode.props as TeleportProps, nodeOps.querySelector ) as Node if (target) { - obs.push(onSubTreeChange(target, () => updateCssVars(vnode))) + if (init) { + obs.push(onSubTreeChange(target, () => updateCssVars(vnode))) + } else { + updateCssVars(vnode) + } } } if (isArray(vnode.children)) { - vnode.children.forEach(n => observeTeleportTarget(n as VNode)) + vnode.children.forEach(n => observeTeleportTarget(n as VNode, init)) } } observeTeleportTarget(instance.subTree) + onUpdated(() => { + observeTeleportTarget(instance.subTree, false) + }) onUnmounted(() => obs.forEach(ob => ob.disconnect())) }) }