]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(v-show): v-show takes higher priority than style attribute (#3230)
authorHcySunYang <HcySunYang@outlook.com>
Thu, 25 Feb 2021 15:26:54 +0000 (23:26 +0800)
committerGitHub <noreply@github.com>
Thu, 25 Feb 2021 15:26:54 +0000 (10:26 -0500)
fix #2757

packages/runtime-dom/__tests__/directives/vShow.spec.ts
packages/runtime-dom/src/directives/vShow.ts
packages/runtime-dom/src/modules/style.ts

index 6c21e5f83f07b42bf48532b9d1b87b052fba1662..545e22b9c75cb937c7c806884dd6f2da7ebcd4db 100644 (file)
@@ -3,9 +3,11 @@ import {
   defineComponent,
   h,
   nextTick,
-  VNode
+  VNode,
+  ref,
+  watch
 } from '@vue/runtime-core'
-import { render, vShow } from '@vue/runtime-dom'
+import { render, Transition, vShow } from '@vue/runtime-dom'
 
 const withVShow = (node: VNode, exp: any) =>
   withDirectives(node, [[vShow, exp]])
@@ -124,4 +126,63 @@ describe('runtime-dom: v-show directive', () => {
     await nextTick()
     expect($div.style.display).toEqual('block')
   })
+
+  // #2583
+  test('the value of `display` set by v-show should not be overwritten by the style attribute when updated', async () => {
+    const style = ref('width: 100px')
+    const display = ref(false)
+    const component = defineComponent({
+      render() {
+        return withVShow(h('div', { style: style.value }), display.value)
+      }
+    })
+    render(h(component), root)
+
+    const $div = root.querySelector('div')
+
+    expect($div.style.display).toEqual('none')
+
+    style.value = 'width: 50px'
+    await nextTick()
+    expect($div.style.display).toEqual('none')
+
+    display.value = true
+    await nextTick()
+    expect($div.style.display).toEqual('')
+  })
+
+  // #2583, #2757
+  test('the value of `display` set by v-show should not be overwritten by the style attribute when updated (with Transition)', async () => {
+    const style = ref('width: 100px')
+    const display = ref(false)
+    const component = defineComponent({
+      setup() {
+        const innerValue = ref(false)
+        watch(display, val => {
+          innerValue.value = val
+        })
+        return () => {
+          return h(Transition, () =>
+            withVShow(
+              h('div', { style: style.value }, innerValue.value),
+              display.value
+            )
+          )
+        }
+      }
+    })
+    render(h(component), root)
+
+    const $div = root.querySelector('div')
+
+    expect($div.style.display).toEqual('none')
+
+    style.value = 'width: 50px'
+    await nextTick()
+    expect($div.style.display).toEqual('none')
+
+    display.value = true
+    await nextTick()
+    expect($div.style.display).toEqual('')
+  })
 })
index f94ac3bae3b92bb7fa8547f779f1ea980ae1ff3e..d9bf3af54874e521af72fefb96bd49cb500f13da 100644 (file)
@@ -20,7 +20,8 @@ export const vShow: ObjectDirective<VShowElement> = {
     }
   },
   updated(el, { value, oldValue }, { transition }) {
-    if (transition && value !== oldValue) {
+    if (!value === !oldValue) return
+    if (transition) {
       if (value) {
         transition.beforeEnter(el)
         setDisplay(el, true)
index 30816b58d83ca1829c428a31e3b8c76425d92b75..1084e5b2f8f623cae25a5abc7a7308074cf8660e 100644 (file)
@@ -9,7 +9,14 @@ export function patchStyle(el: Element, prev: Style, next: Style) {
     el.removeAttribute('style')
   } else if (isString(next)) {
     if (prev !== next) {
+      const current = style.display
       style.cssText = next
+      // 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`.
+      if ('_vod' in el) {
+        style.display = current
+      }
     }
   } else {
     for (const key in next) {