Просмотр исходного кода

fix(transition): avoid move transition for hidden v-show group children (#14896)

edison 2 недель назад
Родитель
Сommit
247965241b

+ 55 - 0
packages-private/vapor-e2e-test/__tests__/transition-group.spec.ts

@@ -603,6 +603,61 @@ describe('vapor transition-group', () => {
     E2E_TIMEOUT,
   )
 
+  test(
+    'v-show enter does not also run move transition',
+    async () => {
+      const btnSelector =
+        '.v-show-enter-does-not-also-run-move-transition > button'
+      const containerSelector =
+        '.v-show-enter-does-not-also-run-move-transition > div'
+
+      click(btnSelector)
+      await nextTick()
+      await nextFrame()
+
+      const items = Array.from(
+        css(containerSelector)
+          .element()
+          .querySelectorAll<HTMLElement>('.show-item'),
+      ).map(node => ({
+        text: node.textContent!.trim(),
+        classes: Array.from(node.classList),
+      }))
+
+      expect(items).toStrictEqual([
+        {
+          text: 'c',
+          classes: ['test', 'show-item', 'group-move'],
+        },
+        {
+          text: 'a',
+          classes: ['test', 'show-item', 'group-move'],
+        },
+        {
+          text: 'b',
+          classes: [
+            'test',
+            'show-item',
+            'group-enter-from',
+            'group-enter-active',
+          ],
+        },
+        {
+          text: 'd',
+          classes: [
+            'test',
+            'show-item',
+            'group-enter-from',
+            'group-enter-active',
+          ],
+        },
+      ])
+
+      await transitionFinish()
+    },
+    E2E_TIMEOUT,
+  )
+
   test('keyed component move after key change', async () => {
     const btnSelector = '.keyed-component-move-after-key-change > button'
     const containerSelector = '.keyed-component-move-after-key-change > div'

+ 40 - 0
packages-private/vapor-e2e-test/transition-group/cases/vapor-transition-group/v-show-enter-does-not-also-run-move-transition.vue

@@ -0,0 +1,40 @@
+<script setup vapor>
+import { ref } from 'vue'
+
+const items = ref(['a', 'b', 'c'])
+const showB = ref(false)
+const showHiddenItem = () => {
+  showB.value = true
+  items.value = ['c', 'a', 'b', 'd']
+}
+</script>
+
+<template>
+  <div class="v-show-enter-does-not-also-run-move-transition">
+    <button @click="showHiddenItem">show hidden item</button>
+    <div>
+      <transition-group name="group" tag="div" class="show-group">
+        <div
+          v-for="item in items"
+          :key="item"
+          v-show="item === 'b' ? showB : true"
+          class="test show-item"
+        >
+          {{ item }}
+        </div>
+      </transition-group>
+    </div>
+  </div>
+</template>
+
+<style>
+.show-group {
+  display: flex;
+  gap: 5px;
+}
+
+.show-item {
+  width: 100px;
+  height: 20px;
+}
+</style>

+ 7 - 1
packages/runtime-vapor/src/components/TransitionGroup.ts

@@ -5,6 +5,7 @@ import {
   type TransitionProps,
   TransitionPropsValidators,
   type TransitionState,
+  type VShowElement,
   baseApplyTranslation,
   callPendingCbs,
   currentInstance,
@@ -17,6 +18,7 @@ import {
   resolveTransitionProps,
   setCurrentInstance,
   useTransitionState,
+  vShowHidden,
   warn,
 } from '@vue/runtime-dom'
 import { extend, isArray } from '@vue/shared'
@@ -166,7 +168,11 @@ const VaporTransitionGroupImpl = defineVaporComponent({
           isValidTransitionBlock(child) && child.$transition
             ? getTransitionElement(child)
             : undefined
-        if (el) {
+        if (
+          el &&
+          // Hidden v-show nodes have no previous layout box to animate from.
+          !(el as VShowElement)[vShowHidden]
+        ) {
           prevChildren.push(child)
           // disabled transition during enter, so the children will be
           // inserted into the correct position immediately. this prevents