Skip to content

Commit

Permalink
fix(sfc/style-vars): properly re-apply style vars on component root e…
Browse files Browse the repository at this point in the history
…lements change

Now uses MutationObserver to ensure it works even for HOCs

fix #3894
  • Loading branch information
yyx990803 committed Jul 16, 2021
1 parent 317654b commit 49dc2dd
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 6 deletions.
37 changes: 36 additions & 1 deletion packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
reactive,
nextTick,
ComponentOptions,
Suspense
Suspense,
FunctionalComponent
} from '@vue/runtime-dom'

describe('useCssVars', () => {
Expand Down Expand Up @@ -142,6 +143,40 @@ describe('useCssVars', () => {
}
})

// #3894
test('with subTree change inside HOC', async () => {
const state = reactive({ color: 'red' })
const value = ref(true)
const root = document.createElement('div')

const Child: FunctionalComponent = (_, { slots }) => slots.default!()

const App = {
setup() {
useCssVars(() => state)
return () =>
h(
Child,
null,
() => (value.value ? [h('div')] : [h('div'), h('div')])
)
}
}

render(h(App), root)
await nextTick()
// css vars use with fallback tree
for (const c of [].slice.call(root.children as any)) {
expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe(`red`)
}

value.value = false
await nextTick()
for (const c of [].slice.call(root.children as any)) {
expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
}
})

test('with createStaticVNode', async () => {
const state = reactive({ color: 'red' })
const root = document.createElement('div')
Expand Down
14 changes: 9 additions & 5 deletions packages/runtime-dom/src/helpers/useCssVars.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
getCurrentInstance,
onMounted,
warn,
VNode,
Fragment,
Static,
onUpdated,
watchEffect
watchPostEffect,
onMounted,
onUnmounted
} from '@vue/runtime-core'
import { ShapeFlags } from '@vue/shared'

Expand All @@ -27,8 +27,12 @@ export function useCssVars(getter: (ctx: any) => Record<string, string>) {

const setVars = () =>
setVarsOnVNode(instance.subTree, getter(instance.proxy!))
onMounted(() => watchEffect(setVars, { flush: 'post' }))
onUpdated(setVars)
watchPostEffect(setVars)
onMounted(() => {
const ob = new MutationObserver(setVars)
ob.observe(instance.subTree.el!.parentNode, { childList: true })
onUnmounted(() => ob.disconnect())
})
}

function setVarsOnVNode(vnode: VNode, vars: Record<string, string>) {
Expand Down

0 comments on commit 49dc2dd

Please sign in to comment.