Skip to content

Commit

Permalink
fix(runtime-core): properly handle inherit transition during clone VN…
Browse files Browse the repository at this point in the history
…ode (#10809)

close #3716
close #10497
close #4091
  • Loading branch information
edison1105 authored Apr 29, 2024
1 parent e8fd644 commit 638a79f
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 8 deletions.
17 changes: 11 additions & 6 deletions packages/runtime-core/src/componentRenderUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export function renderComponentRoot(
propsOptions,
)
}
root = cloneVNode(root, fallthroughAttrs)
root = cloneVNode(root, fallthroughAttrs, false, true)
} else if (__DEV__ && !accessedAttrs && root.type !== Comment) {
const allAttrs = Object.keys(attrs)
const eventAttrs: string[] = []
Expand Down Expand Up @@ -221,10 +221,15 @@ export function renderComponentRoot(
getComponentName(instance.type),
)
}
root = cloneVNode(root, {
class: cls,
style: style,
})
root = cloneVNode(
root,
{
class: cls,
style: style,
},
false,
true,
)
}
}

Expand All @@ -237,7 +242,7 @@ export function renderComponentRoot(
)
}
// clone before mutating since the root may be a hoisted vnode
root = cloneVNode(root)
root = cloneVNode(root, null, false, true)
root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs
}
// inherit transition data
Expand Down
14 changes: 12 additions & 2 deletions packages/runtime-core/src/vnode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,10 +624,11 @@ export function cloneVNode<T, U>(
vnode: VNode<T, U>,
extraProps?: (Data & VNodeProps) | null,
mergeRef = false,
cloneTransition = false,
): VNode<T, U> {
// This is intentionally NOT using spread or extend to avoid the runtime
// key enumeration cost.
const { props, ref, patchFlag, children } = vnode
const { props, ref, patchFlag, children, transition } = vnode
const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props
const cloned: VNode<T, U> = {
__v_isVNode: true,
Expand Down Expand Up @@ -670,7 +671,7 @@ export function cloneVNode<T, U>(
dynamicChildren: vnode.dynamicChildren,
appContext: vnode.appContext,
dirs: vnode.dirs,
transition: vnode.transition,
transition,

// These should technically only be non-null on mounted VNodes. However,
// they *should* be copied for kept-alive vnodes. So we just always copy
Expand All @@ -685,9 +686,18 @@ export function cloneVNode<T, U>(
ctx: vnode.ctx,
ce: vnode.ce,
}

// if the vnode will be replaced by the cloned one, it is necessary
// to clone the transition to ensure that the vnode referenced within
// the transition hooks is fresh.
if (transition && cloneTransition) {
cloned.transition = transition.clone(cloned as VNode)
}

if (__COMPAT__) {
defineLegacyVNodeProperties(cloned as VNode)
}

return cloned
}

Expand Down
48 changes: 48 additions & 0 deletions packages/vue/__tests__/e2e/Transition.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,54 @@ describe('e2e: Transition', () => {
E2E_TIMEOUT,
)

// #3716
test(
'wrapping transition + fallthrough attrs',
async () => {
await page().goto(baseUrl)
await page().waitForSelector('#app')
await page().evaluate(() => {
const { createApp, ref } = (window as any).Vue
createApp({
components: {
'my-transition': {
template: `
<transition foo="1" name="test">
<slot></slot>
</transition>
`,
},
},
template: `
<div id="container">
<my-transition>
<div v-if="toggle">content</div>
</my-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('<div foo="1">content</div>')

await click('#toggleBtn')
// toggle again before leave finishes
await nextTick()
await click('#toggleBtn')

await transitionFinish()
expect(await html('#container')).toBe(
'<div foo="1" class="">content</div>',
)
},
E2E_TIMEOUT,
)

test(
'w/ KeepAlive + unmount innerChild',
async () => {
Expand Down

0 comments on commit 638a79f

Please sign in to comment.