]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(transition): fix broken leave transition on dev root fragment (#5268)
authoredison <daiwei521@126.com>
Thu, 14 Apr 2022 09:10:41 +0000 (17:10 +0800)
committerGitHub <noreply@github.com>
Thu, 14 Apr 2022 09:10:41 +0000 (05:10 -0400)
packages/runtime-core/src/renderer.ts
packages/vue/__tests__/Transition.spec.ts

index 0a215a14b762b6d3bfe218b137ef9f25b6fa60fb..ed698d21f7bb3990f6856fc96fd34af35c2f401e 100644 (file)
@@ -2159,7 +2159,23 @@ function baseCreateRenderer(
   const remove: RemoveFn = vnode => {
     const { type, el, anchor, transition } = vnode
     if (type === Fragment) {
-      removeFragment(el!, anchor!)
+      if (
+        __DEV__ &&
+        vnode.patchFlag > 0 &&
+        vnode.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT &&
+        transition &&
+        !transition.persisted
+      ) {
+        ;(vnode.children as VNode[]).forEach(child => {
+          if (child.type === Comment) {
+            hostRemove(child.el!)
+          } else {
+            remove(child)
+          }
+        })
+      } else {
+        removeFragment(el!, anchor!)
+      }
       return
     }
 
index 97b3ccd96257544e9547ad74407e984bdc81a53a..372049395118ecd8e4f389c077f6123cd2cca890 100644 (file)
@@ -1979,9 +1979,7 @@ describe('e2e: Transition', () => {
         </div>
       `
     }).mount(document.createElement('div'))
-    expect(
-      `invalid <transition> mode: none`
-    ).toHaveBeenWarned()
+    expect(`invalid <transition> mode: none`).toHaveBeenWarned()
   })
 
   // #3227
@@ -2023,4 +2021,74 @@ describe('e2e: Transition', () => {
     expect(outerSpy).toHaveBeenCalledTimes(1)
     expect(root.innerHTML).toBe(`<!---->`)
   })
+
+  test(
+    'should work with dev root fragment',
+    async () => {
+      await page().evaluate(() => {
+        const { createApp, ref } = (window as any).Vue
+        createApp({
+          components: {
+            Comp: {
+              template: `
+                  <!-- Broken! -->
+                  <div><slot /></div>
+                `
+            }
+          },
+          template: `
+            <div id="container">
+              <transition>
+                <Comp class="test" v-if="toggle">      
+                  <div>content</div>
+                </Comp>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+          setup: () => {
+            const toggle = ref(true)
+            const click = () => (toggle.value = !toggle.value)
+            return { toggle, click }
+          }
+        }).mount('#app')
+      })
+      expect(await html('#container')).toBe(
+        '<!-- Broken! --><div class="test"><div>content</div></div>'
+      )
+
+      // leave
+      expect(await classWhenTransitionStart()).toStrictEqual([
+        'test',
+        'v-leave-from',
+        'v-leave-active'
+      ])
+      await nextFrame()
+      expect(await classList('.test')).toStrictEqual([
+        'test',
+        'v-leave-active',
+        'v-leave-to'
+      ])
+      await transitionFinish()
+      expect(await html('#container')).toBe('<!--v-if-->')
+
+      // enter
+      expect(await classWhenTransitionStart()).toStrictEqual([
+        'test',
+        'v-enter-from',
+        'v-enter-active'
+      ])
+      await nextFrame()
+      expect(await classList('.test')).toStrictEqual([
+        'test',
+        'v-enter-active',
+        'v-enter-to'
+      ])
+      await transitionFinish()
+      expect(await html('#container')).toBe(
+        '<!-- Broken! --><div class="test"><div>content</div></div>'
+      )
+    },
+    E2E_TIMEOUT
+  )
 })