Explorar el Código

fix(sfc/cssVars): fix loss of CSS v-bind variables when setting inline style with string value (#9824)

close #9821
丶远方 hace 2 años
padre
commit
0a387dfb1d

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

@@ -293,4 +293,35 @@ describe('useCssVars', () => {
     await nextTick()
     expect(target.children.length).toBe(0)
   })
+
+  test('with string style', async () => {
+    document.body.innerHTML = ''
+    const state = reactive({ color: 'red' })
+    const root = document.createElement('div')
+    const disabled = ref(false)
+
+    const App = {
+      setup() {
+        useCssVars(() => state)
+        return () => [
+          h(
+            'div',
+            { style: disabled.value ? 'pointer-events: none' : undefined },
+            'foo'
+          )
+        ]
+      }
+    }
+    render(h(App), root)
+    await nextTick()
+    for (const c of [].slice.call(root.children as any)) {
+      expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
+    }
+    disabled.value = true
+    await nextTick()
+
+    for (const c of [].slice.call(root.children as any)) {
+      expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
+    }
+  })
 })

+ 4 - 0
packages/runtime-dom/src/helpers/useCssVars.ts

@@ -10,6 +10,7 @@ import {
 } from '@vue/runtime-core'
 import { ShapeFlags } from '@vue/shared'
 
+export const CSS_VAR_TEXT = Symbol(__DEV__ ? 'CSS_VAR_TEXT' : '')
 /**
  * Runtime helper for SFC's CSS variable injection feature.
  * @private
@@ -79,8 +80,11 @@ function setVarsOnVNode(vnode: VNode, vars: Record<string, string>) {
 function setVarsOnNode(el: Node, vars: Record<string, string>) {
   if (el.nodeType === 1) {
     const style = (el as HTMLElement).style
+    let cssText = ''
     for (const key in vars) {
       style.setProperty(`--${key}`, vars[key])
+      cssText += `--${key}: ${vars[key]};`
     }
+    ;(style as any)[CSS_VAR_TEXT] = cssText
   }
 }

+ 6 - 0
packages/runtime-dom/src/modules/style.ts

@@ -1,6 +1,7 @@
 import { isString, hyphenate, capitalize, isArray } from '@vue/shared'
 import { camelize, warn } from '@vue/runtime-core'
 import { vShowOldKey } from '../directives/vShow'
+import { CSS_VAR_TEXT } from '../helpers/useCssVars'
 
 type Style = string | Record<string, string | string[]> | null
 
@@ -22,6 +23,11 @@ export function patchStyle(el: Element, prev: Style, next: Style) {
     const currentDisplay = style.display
     if (isCssString) {
       if (prev !== next) {
+        // #9821
+        const cssVarText = (style as any)[CSS_VAR_TEXT]
+        if (cssVarText) {
+          ;(next as string) += ';' + cssVarText
+        }
         style.cssText = next as string
       }
     } else if (prev) {