Skip to content

Commit 5ad4036

Browse files
authored
fix(v-show): v-show takes higher priority than style attribute (#3230)
fix #2757
1 parent 45fae9d commit 5ad4036

File tree

3 files changed

+72
-3
lines changed

3 files changed

+72
-3
lines changed

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

+63-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import {
33
defineComponent,
44
h,
55
nextTick,
6-
VNode
6+
VNode,
7+
ref,
8+
watch
79
} from '@vue/runtime-core'
8-
import { render, vShow } from '@vue/runtime-dom'
10+
import { render, Transition, vShow } from '@vue/runtime-dom'
911

1012
const withVShow = (node: VNode, exp: any) =>
1113
withDirectives(node, [[vShow, exp]])
@@ -124,4 +126,63 @@ describe('runtime-dom: v-show directive', () => {
124126
await nextTick()
125127
expect($div.style.display).toEqual('block')
126128
})
129+
130+
// #2583
131+
test('the value of `display` set by v-show should not be overwritten by the style attribute when updated', async () => {
132+
const style = ref('width: 100px')
133+
const display = ref(false)
134+
const component = defineComponent({
135+
render() {
136+
return withVShow(h('div', { style: style.value }), display.value)
137+
}
138+
})
139+
render(h(component), root)
140+
141+
const $div = root.querySelector('div')
142+
143+
expect($div.style.display).toEqual('none')
144+
145+
style.value = 'width: 50px'
146+
await nextTick()
147+
expect($div.style.display).toEqual('none')
148+
149+
display.value = true
150+
await nextTick()
151+
expect($div.style.display).toEqual('')
152+
})
153+
154+
// #2583, #2757
155+
test('the value of `display` set by v-show should not be overwritten by the style attribute when updated (with Transition)', async () => {
156+
const style = ref('width: 100px')
157+
const display = ref(false)
158+
const component = defineComponent({
159+
setup() {
160+
const innerValue = ref(false)
161+
watch(display, val => {
162+
innerValue.value = val
163+
})
164+
return () => {
165+
return h(Transition, () =>
166+
withVShow(
167+
h('div', { style: style.value }, innerValue.value),
168+
display.value
169+
)
170+
)
171+
}
172+
}
173+
})
174+
render(h(component), root)
175+
176+
const $div = root.querySelector('div')
177+
178+
expect($div.style.display).toEqual('none')
179+
180+
style.value = 'width: 50px'
181+
await nextTick()
182+
expect($div.style.display).toEqual('none')
183+
184+
display.value = true
185+
await nextTick()
186+
expect($div.style.display).toEqual('')
187+
})
127188
})

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ export const vShow: ObjectDirective<VShowElement> = {
2020
}
2121
},
2222
updated(el, { value, oldValue }, { transition }) {
23-
if (transition && value !== oldValue) {
23+
if (!value === !oldValue) return
24+
if (transition) {
2425
if (value) {
2526
transition.beforeEnter(el)
2627
setDisplay(el, true)

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

+7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ export function patchStyle(el: Element, prev: Style, next: Style) {
99
el.removeAttribute('style')
1010
} else if (isString(next)) {
1111
if (prev !== next) {
12+
const current = style.display
1213
style.cssText = next
14+
// indicates that the `display` of the element is controlled by `v-show`,
15+
// so we always keep the current `display` value regardless of the `style` value,
16+
// thus handing over control to `v-show`.
17+
if ('_vod' in el) {
18+
style.display = current
19+
}
1320
}
1421
} else {
1522
for (const key in next) {

0 commit comments

Comments
 (0)