From 0a387dfb1d04afb6eae4296b6da76dfdaca77af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=B6=E8=BF=9C=E6=96=B9?= Date: Fri, 15 Dec 2023 09:56:01 +0800 Subject: [PATCH] fix(sfc/cssVars): fix loss of CSS v-bind variables when setting inline style with string value (#9824) close #9821 --- .../__tests__/helpers/useCssVars.spec.ts | 31 +++++++++++++++++++ .../runtime-dom/src/helpers/useCssVars.ts | 4 +++ packages/runtime-dom/src/modules/style.ts | 6 ++++ 3 files changed, 41 insertions(+) diff --git a/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts b/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts index 5792a0107b1..0d8b8d0d26e 100644 --- a/packages/runtime-dom/__tests__/helpers/useCssVars.spec.ts +++ b/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') + } + }) }) diff --git a/packages/runtime-dom/src/helpers/useCssVars.ts b/packages/runtime-dom/src/helpers/useCssVars.ts index e0a95c9ca99..4bd9838ba75 100644 --- a/packages/runtime-dom/src/helpers/useCssVars.ts +++ b/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) { function setVarsOnNode(el: Node, vars: Record) { 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 } } diff --git a/packages/runtime-dom/src/modules/style.ts b/packages/runtime-dom/src/modules/style.ts index c18fd8aa9d5..cb4ee777251 100644 --- a/packages/runtime-dom/src/modules/style.ts +++ b/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 | 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) {