Skip to content

Commit 721afd1

Browse files
committed
feat(transition-group): enhance TransitionGroup to trigger update hooks manually
1 parent abe8fc2 commit 721afd1

File tree

5 files changed

+46
-19
lines changed

5 files changed

+46
-19
lines changed

packages/compiler-vapor/src/generators/component.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,7 @@ import { genEventHandler } from './event'
4040
import { genDirectiveModifiers, genDirectivesForElement } from './directive'
4141
import { genBlock } from './block'
4242
import { genModelHandler } from './vModel'
43-
import {
44-
isBuiltInComponent,
45-
isKeepAliveTag,
46-
isTeleportTag,
47-
isTransitionGroupTag,
48-
} from '../utils'
43+
import { isBuiltInComponent } from '../utils'
4944

5045
export function genCreateComponent(
5146
operation: CreateComponentIRNode,
@@ -465,15 +460,7 @@ function genSlotBlockWithProps(oper: SlotBlockIRNode, context: CodegenContext) {
465460
]
466461
}
467462

468-
if (
469-
node.type === NodeTypes.ELEMENT &&
470-
// Not a real component
471-
!isTeleportTag(node.tag) &&
472-
// Needs to determine whether to activate/deactivate based on instance.parent being KeepAlive
473-
!isKeepAliveTag(node.tag) &&
474-
// Slot updates need to trigger TransitionGroup's onBeforeUpdate/onUpdated hook
475-
!isTransitionGroupTag(node.tag)
476-
) {
463+
if (node.type === NodeTypes.ELEMENT) {
477464
// wrap with withVaporCtx to ensure correct currentInstance inside slot
478465
blockFn = [`${context.helper('withVaporCtx')}(`, ...blockFn, `)`]
479466
}

packages/runtime-vapor/src/apiCreateFor.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
isLastInsertion,
4040
resetInsertionState,
4141
} from './insertionState'
42+
import { triggerTransitionGroupUpdate } from './components/TransitionGroup'
4243

4344
class ForBlock extends VaporFragment {
4445
scope: EffectScope | undefined
@@ -130,6 +131,12 @@ export const createFor = (
130131
newBlocks = new Array(newLength)
131132
let isFallback = false
132133

134+
// trigger TransitionGroup update hooks
135+
const transitionHooks = frag.$transition
136+
if (transitionHooks && transitionHooks.group) {
137+
triggerTransitionGroupUpdate(transitionHooks)
138+
}
139+
133140
const prevSub = setActiveSub()
134141

135142
if (!isMounted) {

packages/runtime-vapor/src/block.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export interface VaporTransitionHooks extends TransitionHooks {
2929
// mark transition hooks as disabled so that it skips during
3030
// inserting
3131
disabled?: boolean
32+
// mark transition hooks as group so that it triggers TransitionGroup update hooks
33+
// in vFor renderList function
34+
group?: boolean
3235
}
3336

3437
export interface TransitionOptions {

packages/runtime-vapor/src/components/Transition.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ export function applyTransitionHooks(
233233
return hooks
234234
}
235235

236-
const { props, instance, state, delayedLeave } = hooks
236+
const { props, instance, state, delayedLeave, group } = hooks
237237
let resolvedHooks = resolveTransitionHooks(
238238
child,
239239
props,
@@ -242,6 +242,7 @@ export function applyTransitionHooks(
242242
hooks => (resolvedHooks = hooks as VaporTransitionHooks),
243243
)
244244
resolvedHooks.delayedLeave = delayedLeave
245+
resolvedHooks.group = group
245246
child.$transition = resolvedHooks
246247
if (isFrag) setTransitionHooksOnFragment(block, resolvedHooks)
247248

@@ -365,6 +366,9 @@ export function setTransitionHooksOnFragment(
365366
): void {
366367
if (isFragment(block)) {
367368
block.$transition = hooks
369+
if (block.nodes && isFragment(block.nodes)) {
370+
setTransitionHooksOnFragment(block.nodes, hooks)
371+
}
368372
} else if (isArray(block)) {
369373
for (let i = 0; i < block.length; i++) {
370374
setTransitionHooksOnFragment(block[i], hooks)

packages/runtime-vapor/src/components/TransitionGroup.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import {
1010
hasCSSTransform,
1111
onBeforeUpdate,
1212
onUpdated,
13+
queuePostFlushCb,
1314
resolveTransitionProps,
1415
useTransitionState,
1516
warn,
1617
} from '@vue/runtime-dom'
17-
import { extend, isArray } from '@vue/shared'
18+
import { extend, invokeArrayFns, isArray } from '@vue/shared'
1819
import {
1920
type Block,
2021
type TransitionBlock,
@@ -126,17 +127,22 @@ export const VaporTransitionGroup: ObjectVaporComponent = decorate({
126127
props: cssTransitionProps,
127128
state,
128129
instance,
130+
group: true,
129131
} as VaporTransitionHooks)
130132

131133
children = getTransitionBlocks(slottedBlock)
132134
for (let i = 0; i < children.length; i++) {
133135
const child = children[i]
134136
if (isValidTransitionBlock(child)) {
135137
if (child.$key != null) {
136-
setTransitionHooks(
138+
const hooks = resolveTransitionHooks(
137139
child,
138-
resolveTransitionHooks(child, cssTransitionProps, state, instance!),
140+
cssTransitionProps,
141+
state,
142+
instance!,
139143
)
144+
hooks.group = true
145+
setTransitionHooks(child, hooks)
140146
} else if (__DEV__ && child.$key == null) {
141147
warn(`<transition-group> children must be keyed`)
142148
}
@@ -221,3 +227,23 @@ function getFirstConnectedChild(
221227
if (el.isConnected) return el
222228
}
223229
}
230+
231+
/**
232+
* The implementation of TransitionGroup relies on the onBeforeUpdate and onUpdated hooks.
233+
* However, when the slot content of TransitionGroup updates, it does not trigger the
234+
* onBeforeUpdate and onUpdated hooks. Therefore, it is necessary to manually trigger
235+
* the TransitionGroup update hooks to ensure its proper work.
236+
*/
237+
export function triggerTransitionGroupUpdate(
238+
transition: VaporTransitionHooks,
239+
): void {
240+
const { instance } = transition
241+
if (!instance.isUpdating) {
242+
instance.isUpdating = true
243+
if (instance.bu) invokeArrayFns(instance.bu)
244+
queuePostFlushCb(() => {
245+
instance.isUpdating = false
246+
if (instance.u) invokeArrayFns(instance.u)
247+
})
248+
}
249+
}

0 commit comments

Comments
 (0)