]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(hydration): handle transition appear hydration edge case (#13339)
authoredison <daiwei521@126.com>
Tue, 20 May 2025 00:28:43 +0000 (08:28 +0800)
committerGitHub <noreply@github.com>
Tue, 20 May 2025 00:28:43 +0000 (08:28 +0800)
close #13335

packages/runtime-core/__tests__/hydration.spec.ts
packages/runtime-core/src/hydration.ts

index 20519cf997fe0668819d98291972b4e920151a35..4a9e0fac2b6e8f1f69215d47219556d5bcbb7749 100644 (file)
@@ -1654,6 +1654,29 @@ describe('SSR hydration', () => {
     expect(`mismatch`).not.toHaveBeenWarned()
   })
 
+  test('transition appear work with pre-existing class', () => {
+    const { vnode, container } = mountWithHydration(
+      `<template><div class="foo">foo</div></template>`,
+      () =>
+        h(
+          Transition,
+          { appear: true },
+          {
+            default: () => h('div', { class: 'foo' }, 'foo'),
+          },
+        ),
+    )
+    expect(container.firstChild).toMatchInlineSnapshot(`
+      <div
+        class="foo v-enter-from v-enter-active"
+      >
+        foo
+      </div>
+    `)
+    expect(vnode.el).toBe(container.firstChild)
+    expect(`mismatch`).not.toHaveBeenWarned()
+  })
+
   test('transition appear with v-if', () => {
     const show = false
     const { vnode, container } = mountWithHydration(
index a94ff3568107e6c20d383eeb4e5e839012825ee2..6ffdbc68de4109816bd2c4fa2dd1dcfcc018d4e3 100644 (file)
@@ -398,9 +398,11 @@ export function createHydrationFunctions(
           parentComponent.vnode.props.appear
 
         const content = (el as HTMLTemplateElement).content
-          .firstChild as Element
+          .firstChild as Element & { $cls?: string }
 
         if (needCallTransitionHooks) {
+          const cls = content.getAttribute('class')
+          if (cls) content.$cls = cls
           transition!.beforeEnter(content)
         }
 
@@ -786,7 +788,7 @@ export function createHydrationFunctions(
  * Dev only
  */
 function propHasMismatch(
-  el: Element,
+  el: Element & { $cls?: string },
   key: string,
   clientValue: any,
   vnode: VNode,
@@ -799,7 +801,12 @@ function propHasMismatch(
   if (key === 'class') {
     // classes might be in different order, but that doesn't affect cascade
     // so we just need to check if the class lists contain the same classes.
-    actual = el.getAttribute('class')
+    if (el.$cls) {
+      actual = el.$cls
+      delete el.$cls
+    } else {
+      actual = el.getAttribute('class')
+    }
     expected = normalizeClass(clientValue)
     if (!isSetEqual(toClassSet(actual || ''), toClassSet(expected))) {
       mismatchType = MismatchTypes.CLASS