Skip to content

Commit c224897

Browse files
authored
fix(runtime-dom): ensure v-show respects display value set via v-bind (#10297)
close #10151
1 parent 5d48844 commit c224897

File tree

3 files changed

+108
-2
lines changed

3 files changed

+108
-2
lines changed

packages/runtime-dom/__tests__/directives/vShow.spec.ts

+98
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,102 @@ describe('runtime-dom: v-show directive', () => {
211211
await nextTick()
212212
expect($div.style.display).toEqual('')
213213
})
214+
215+
// #10151
216+
test('should respect the display value when v-show value is true', async () => {
217+
const isVisible = ref(false)
218+
const useDisplayStyle = ref(true)
219+
const compStyle = ref({
220+
display: 'none',
221+
})
222+
const withoutDisplayStyle = {
223+
margin: '10px',
224+
}
225+
226+
const Component = {
227+
setup() {
228+
return () => {
229+
return withVShow(
230+
h('div', {
231+
style: useDisplayStyle.value
232+
? compStyle.value
233+
: withoutDisplayStyle,
234+
}),
235+
isVisible.value,
236+
)
237+
}
238+
},
239+
}
240+
render(h(Component), root)
241+
242+
const $div = root.children[0]
243+
244+
expect($div.style.display).toEqual('none')
245+
246+
isVisible.value = true
247+
await nextTick()
248+
expect($div.style.display).toEqual('none')
249+
250+
compStyle.value.display = 'block'
251+
await nextTick()
252+
expect($div.style.display).toEqual('block')
253+
254+
compStyle.value.display = 'inline-block'
255+
await nextTick()
256+
expect($div.style.display).toEqual('inline-block')
257+
258+
isVisible.value = false
259+
await nextTick()
260+
expect($div.style.display).toEqual('none')
261+
262+
isVisible.value = true
263+
await nextTick()
264+
expect($div.style.display).toEqual('inline-block')
265+
266+
useDisplayStyle.value = false
267+
await nextTick()
268+
expect($div.style.display).toEqual('')
269+
expect(getComputedStyle($div).display).toEqual('block')
270+
271+
isVisible.value = false
272+
await nextTick()
273+
expect($div.style.display).toEqual('none')
274+
275+
isVisible.value = true
276+
await nextTick()
277+
expect($div.style.display).toEqual('')
278+
})
279+
280+
// #10294
281+
test('should record display by vShowOldKey only when display exists in style', async () => {
282+
const isVisible = ref(false)
283+
const style = ref({
284+
margin: '10px',
285+
})
286+
287+
const Component = {
288+
setup() {
289+
return () => {
290+
return withVShow(
291+
h('div', {
292+
style: style.value,
293+
}),
294+
isVisible.value,
295+
)
296+
}
297+
},
298+
}
299+
render(h(Component), root)
300+
const $div = root.children[0]
301+
302+
expect($div.style.display).toEqual('none')
303+
304+
style.value.margin = '20px'
305+
await nextTick()
306+
expect($div.style.display).toEqual('none')
307+
308+
isVisible.value = true
309+
await nextTick()
310+
expect($div.style.display).toEqual('')
311+
})
214312
})

packages/runtime-dom/src/directives/vShow.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const vShow: ObjectDirective<VShowElement> & { name?: 'show' } = {
2222
}
2323
},
2424
updated(el, { value, oldValue }, { transition }) {
25-
if (!value === !oldValue) return
25+
if (!value === !oldValue && el.style.display === el[vShowOldKey]) return
2626
if (transition) {
2727
if (value) {
2828
transition.beforeEnter(el)

packages/runtime-dom/src/modules/style.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ import { CSS_VAR_TEXT } from '../helpers/useCssVars'
55

66
type Style = string | Record<string, string | string[]> | null
77

8+
const displayRE = /(^|;)\s*display\s*:/
9+
810
export function patchStyle(el: Element, prev: Style, next: Style) {
911
const style = (el as HTMLElement).style
10-
const currentDisplay = style.display
1112
const isCssString = isString(next)
13+
const currentDisplay = style.display
14+
let hasControlledDisplay = false
1215
if (next && !isCssString) {
1316
if (prev && !isString(prev)) {
1417
for (const key in prev) {
@@ -18,6 +21,9 @@ export function patchStyle(el: Element, prev: Style, next: Style) {
1821
}
1922
}
2023
for (const key in next) {
24+
if (key === 'display') {
25+
hasControlledDisplay = true
26+
}
2127
setStyle(style, key, next[key])
2228
}
2329
} else {
@@ -29,6 +35,7 @@ export function patchStyle(el: Element, prev: Style, next: Style) {
2935
;(next as string) += ';' + cssVarText
3036
}
3137
style.cssText = next as string
38+
hasControlledDisplay = displayRE.test(next)
3239
}
3340
} else if (prev) {
3441
el.removeAttribute('style')
@@ -38,6 +45,7 @@ export function patchStyle(el: Element, prev: Style, next: Style) {
3845
// so we always keep the current `display` value regardless of the `style`
3946
// value, thus handing over control to `v-show`.
4047
if (vShowOldKey in el) {
48+
el[vShowOldKey] = hasControlledDisplay ? style.display : ''
4149
style.display = currentDisplay
4250
}
4351
}

0 commit comments

Comments
 (0)