mirror of https://github.com/vuejs/core.git
fix(TransitionGroup): avoid set transition hooks for comment nodes and text nodes (#9421)
close #4621 close #4622 close #5153 close #5168 close #7898 close #9067
This commit is contained in:
parent
c4684d3161
commit
140a7681cc
|
@ -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++) {
|
||||
|
@ -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)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue