diff --git a/packages/runtime-dom/src/directives/vShow.ts b/packages/runtime-dom/src/directives/vShow.ts index 5bf48b277d9..9cf35bb9a9d 100644 --- a/packages/runtime-dom/src/directives/vShow.ts +++ b/packages/runtime-dom/src/directives/vShow.ts @@ -1,10 +1,12 @@ import type { ObjectDirective } from '@vue/runtime-core' export const vShowOriginalDisplay = Symbol('_vod') +export const vShowHidden = Symbol('_vsh') -interface VShowElement extends HTMLElement { +export interface VShowElement extends HTMLElement { // _vod = vue original display [vShowOriginalDisplay]: string + [vShowHidden]: boolean } export const vShow: ObjectDirective & { name?: 'show' } = { @@ -23,11 +25,7 @@ export const vShow: ObjectDirective & { name?: 'show' } = { } }, updated(el, { value, oldValue }, { transition }) { - if ( - !value === !oldValue && - (el.style.display === el[vShowOriginalDisplay] || !value) - ) - return + if (!value === !oldValue) return if (transition) { if (value) { transition.beforeEnter(el) @@ -53,6 +51,7 @@ if (__DEV__) { function setDisplay(el: VShowElement, value: unknown): void { el.style.display = value ? el[vShowOriginalDisplay] : 'none' + el[vShowHidden] = !value } // SSR vnode transforms, only used when user includes client-oriented render diff --git a/packages/runtime-dom/src/modules/style.ts b/packages/runtime-dom/src/modules/style.ts index 1f45966c3c4..35d714ff085 100644 --- a/packages/runtime-dom/src/modules/style.ts +++ b/packages/runtime-dom/src/modules/style.ts @@ -1,6 +1,10 @@ import { capitalize, hyphenate, isArray, isString } from '@vue/shared' import { camelize, warn } from '@vue/runtime-core' -import { vShowOriginalDisplay } from '../directives/vShow' +import { + type VShowElement, + vShowHidden, + vShowOriginalDisplay, +} from '../directives/vShow' import { CSS_VAR_TEXT } from '../helpers/useCssVars' type Style = string | Record | null @@ -10,7 +14,6 @@ const displayRE = /(^|;)\s*display\s*:/ export function patchStyle(el: Element, prev: Style, next: Style) { const style = (el as HTMLElement).style const isCssString = isString(next) - const currentDisplay = style.display let hasControlledDisplay = false if (next && !isCssString) { if (prev) { @@ -50,12 +53,14 @@ export function patchStyle(el: Element, prev: Style, next: Style) { el.removeAttribute('style') } } - // indicates that the `display` of the element is controlled by `v-show`, - // so we always keep the current `display` value regardless of the `style` - // value, thus handing over control to `v-show`. + // indicates the element also has `v-show`. if (vShowOriginalDisplay in el) { + // make v-show respect the current v-bind style display when shown el[vShowOriginalDisplay] = hasControlledDisplay ? style.display : '' - style.display = currentDisplay + // if v-show is in hidden state, v-show has higher priority + if ((el as VShowElement)[vShowHidden]) { + style.display = 'none' + } } }