Skip to content

Commit

Permalink
fix(TransitionGroup): avoid set transition hooks for comment nodes an…
Browse files Browse the repository at this point in the history
…d text nodes (vuejs#9421)

close vuejs#4621
close vuejs#4622
close vuejs#5153
close vuejs#5168
close vuejs#7898
close vuejs#9067
  • Loading branch information
edison1105 authored and lynxlangya committed May 30, 2024
1 parent 4dcecc5 commit 64ed0e0
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 12 deletions.
35 changes: 23 additions & 12 deletions packages/runtime-dom/src/components/TransitionGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,29 @@ const TransitionGroupImpl: ComponentOptions = {
tag = 'span'
}

prevChildren = children
prevChildren = []
if (children) {
for (let i = 0; i < children.length; i++) {
const child = children[i]
if (child.el && child.el instanceof Element) {
prevChildren.push(child)
setTransitionHooks(
child,
resolveTransitionHooks(
child,
cssTransitionProps,
state,
instance,
),
)
positionMap.set(
child,
(child.el as Element).getBoundingClientRect(),
)
}
}
}

children = slots.default ? getTransitionRawChildren(slots.default()) : []

for (let i = 0; i < children.length; i++) {
Expand All @@ -127,17 +149,6 @@ const TransitionGroupImpl: ComponentOptions = {
}
}

if (prevChildren) {
for (let i = 0; i < prevChildren.length; i++) {
const child = prevChildren[i]
setTransitionHooks(
child,
resolveTransitionHooks(child, cssTransitionProps, state, instance),
)
positionMap.set(child, (child.el as Element).getBoundingClientRect())
}
}

return createVNode(tag, null, children)
}
},
Expand Down
122 changes: 122 additions & 0 deletions packages/vue/__tests__/e2e/TransitionGroup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -508,4 +508,126 @@ describe('e2e: TransitionGroup', () => {

expect(`<TransitionGroup> children must be keyed`).toHaveBeenWarned()
})

// #5168, #7898, #9067
test(
'avoid set transition hooks for comment node',
async () => {
await page().evaluate(duration => {
const { createApp, ref, h, createCommentVNode } = (window as any).Vue

const show = ref(false)
createApp({
template: `
<div id="container">
<transition-group name="test">
<div v-for="item in items" :key="item" class="test">{{item}}</div>
<Child key="child"/>
</transition-group>
</div>
<button id="toggleBtn" @click="click">button</button>
`,
components: {
Child: {
setup() {
return () =>
show.value
? h('div', { class: 'test' }, 'child')
: createCommentVNode('v-if', true)
},
},
},
setup: () => {
const items = ref([])
const click = () => {
items.value = ['a', 'b', 'c']
setTimeout(() => {
show.value = true
}, duration)
}
return { click, items }
},
}).mount('#app')
}, duration)

expect(await html('#container')).toBe(`<!--v-if-->`)

expect(await htmlWhenTransitionStart()).toBe(
`<div class="test test-enter-from test-enter-active">a</div>` +
`<div class="test test-enter-from test-enter-active">b</div>` +
`<div class="test test-enter-from test-enter-active">c</div>` +
`<!--v-if-->`,
)

await transitionFinish(duration)
await nextFrame()
expect(await html('#container')).toBe(
`<div class="test">a</div>` +
`<div class="test">b</div>` +
`<div class="test">c</div>` +
`<div class="test test-enter-active test-enter-to">child</div>`,
)

await transitionFinish(duration)
expect(await html('#container')).toBe(
`<div class="test">a</div>` +
`<div class="test">b</div>` +
`<div class="test">c</div>` +
`<div class="test">child</div>`,
)
},
E2E_TIMEOUT,
)

// #4621, #4622, #5153
test(
'avoid set transition hooks for text node',
async () => {
await page().evaluate(() => {
const { createApp, ref } = (window as any).Vue
const app = createApp({
template: `
<div id="container">
<transition-group name="test">
<div class="test">foo</div>
<div class="test" v-if="show">bar</div>
</transition-group>
</div>
<button id="toggleBtn" @click="click">button</button>
`,
setup: () => {
const show = ref(false)
const click = () => {
show.value = true
}
return { show, click }
},
})

app.config.compilerOptions.whitespace = 'preserve'
app.mount('#app')
})

expect(await html('#container')).toBe(`<div class="test">foo</div>` + ` `)

expect(await htmlWhenTransitionStart()).toBe(
`<div class="test">foo</div>` +
` ` +
`<div class="test test-enter-from test-enter-active">bar</div>`,
)

await nextFrame()
expect(await html('#container')).toBe(
`<div class="test">foo</div>` +
` ` +
`<div class="test test-enter-active test-enter-to">bar</div>`,
)

await transitionFinish(duration)
expect(await html('#container')).toBe(
`<div class="test">foo</div>` + ` ` + `<div class="test">bar</div>`,
)
},
E2E_TIMEOUT,
)
})

0 comments on commit 64ed0e0

Please sign in to comment.