Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 084389e

Browse files
authored
fix(runtime-dom): ensure css vars deps tracking when component has no DOM on mount (#14299)
1 parent e77b6e1 commit 084389e

3 files changed

Lines changed: 78 additions & 7 deletions

File tree

‎packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,4 +488,34 @@ describe('useCssVars', () => {
488488
expect(style.getPropertyValue('--foo')).toBe('initial')
489489
expect(style.getPropertyValue('--bar')).toBe('initial')
490490
})
491+
492+
test('with v-if initial false then update css vars', async () => {
493+
const state = reactive({ color: 'red' })
494+
const root = document.createElement('div')
495+
const show = ref(false)
496+
497+
const App = {
498+
setup() {
499+
useCssVars(() => state)
500+
return () => (show.value ? h('div') : null)
501+
},
502+
}
503+
504+
render(h(App), root)
505+
await nextTick()
506+
expect(root.children.length).toBe(0)
507+
508+
// toggle v-if to true
509+
show.value = true
510+
await nextTick()
511+
expect(root.children.length).toBe(1)
512+
let el = root.children[0] as HTMLElement
513+
expect(el.style.getPropertyValue(`--color`)).toBe('red')
514+
515+
// update css vars
516+
state.color = 'green'
517+
await nextTick()
518+
el = root.children[0] as HTMLElement
519+
expect(el.style.getPropertyValue(`--color`)).toBe('green')
520+
})
491521
})

‎packages/runtime-dom/src/helpers/useCssVars.ts‎

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
warn,
1212
watch,
1313
} from '@vue/runtime-core'
14-
import { NOOP, ShapeFlags, normalizeCssVarValue } from '@vue/shared'
14+
import { NOOP, ShapeFlags, extend, normalizeCssVarValue } from '@vue/shared'
1515

1616
export const CSS_VAR_TEXT: unique symbol = Symbol(__DEV__ ? 'CSS_VAR_TEXT' : '')
1717
/**
@@ -99,22 +99,31 @@ export function baseUseCssVars(
9999
).forEach(node => setVarsOnNode(node, vars))
100100
})
101101

102-
const applyCssCars = () => {
103-
const vars = getVars()
102+
const applyCssVars = (vars = getVars()) => {
104103
setVars(vars)
105104
updateTeleports(vars)
106105
}
107106

108107
// handle cases where child component root is affected
109108
// and triggers reflow in onMounted
110109
onBeforeUpdate(() => {
111-
queuePostFlushCb(applyCssCars)
110+
queuePostFlushCb(applyCssVars)
112111
})
113112

114113
onMounted(() => {
115114
// run setVars synchronously here, but run as post-effect on changes
116-
watch(applyCssCars, NOOP, { flush: 'post' })
117-
const ob = new MutationObserver(applyCssCars)
115+
watch(
116+
() => {
117+
const vars = getVars()
118+
// access all properties to ensure dependency tracking
119+
// even if there are no DOM elements to receive vars yet
120+
extend({}, vars)
121+
applyCssVars(vars)
122+
},
123+
NOOP,
124+
{ flush: 'post' },
125+
)
126+
const ob = new MutationObserver(() => applyCssVars())
118127
ob.observe(getParentNode(), { childList: true })
119128
onUnmounted(() => ob.disconnect())
120129
})

‎packages/runtime-vapor/__tests__/helpers/useCssVars.spec.ts‎

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ describe('useVaporCssVars', () => {
297297
expect(host.children[0].outerHTML.includes('data-v-owner')).toBe(true)
298298
})
299299

300-
test('with teleport and nested component', async () => {
300+
test('with teleport and nested fragment', async () => {
301301
const state = reactive({ color: 'red' })
302302
const target = document.createElement('div')
303303
document.body.appendChild(target)
@@ -517,4 +517,36 @@ describe('useVaporCssVars', () => {
517517

518518
expect(root.innerHTML).toBe(`<!--for-->`)
519519
})
520+
521+
test('with v-if initial false then update css vars', async () => {
522+
const state = reactive({ color: 'red' })
523+
const root = document.createElement('div')
524+
const toggle = ref(false)
525+
526+
define({
527+
setup() {
528+
useVaporCssVars(() => state)
529+
return createIf(
530+
() => toggle.value,
531+
() => template('<div></div>')(),
532+
)
533+
},
534+
}).render({}, root)
535+
536+
await nextTick()
537+
expect(root.children.length).toBe(0)
538+
539+
// toggle v-if to true
540+
toggle.value = true
541+
await nextTick()
542+
expect(root.children.length).toBe(1)
543+
let el = root.children[0] as HTMLElement
544+
expect(el.style.getPropertyValue(`--color`)).toBe('red')
545+
546+
// update css vars
547+
state.color = 'green'
548+
await nextTick()
549+
el = root.children[0] as HTMLElement
550+
expect(el.style.getPropertyValue(`--color`)).toBe('green')
551+
})
520552
})

0 commit comments

Comments
 (0)