From: daiwei Date: Fri, 28 Feb 2025 01:45:04 +0000 (+0800) Subject: refactor: reuse code from BaseTransition X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a8140ac826a15cfdf19af9b38ae1c6600dc60574;p=thirdparty%2Fvuejs%2Fcore.git refactor: reuse code from BaseTransition --- diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index 673d30a777..c59fd7338b 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -25,7 +25,7 @@ import { SchedulerJobFlags } from '../scheduler' type Hook void> = T | T[] -const leaveCbKey: unique symbol = Symbol('_leaveCb') +export const leaveCbKey: unique symbol = Symbol('_leaveCb') const enterCbKey: unique symbol = Symbol('_enterCb') export interface BaseTransitionProps { @@ -88,7 +88,7 @@ export interface TransitionState { isUnmounting: boolean // Track pending leave callbacks for children of the same key. // This is used to force remove leaving a child when a new copy is entering. - leavingVNodes: Map> + leavingVNodes: Map> } export interface TransitionElement { @@ -319,6 +319,13 @@ function getLeavingNodesForType( return leavingVNodesCache } +export interface TransitionHooksContext { + setLeavingNodeCache: () => void + unsetLeavingNodeCache: () => void + earlyRemove: () => void + cloneHooks: (node: any) => TransitionHooks +} + // The transition hooks are attached to the vnode as vnode.transition // and will be called at appropriate timing in the renderer. export function resolveTransitionHooks( @@ -328,6 +335,57 @@ export function resolveTransitionHooks( instance: GenericComponentInstance, postClone?: (hooks: TransitionHooks) => void, ): TransitionHooks { + const key = String(vnode.key) + const leavingVNodesCache = getLeavingNodesForType(state, vnode) + const context: TransitionHooksContext = { + setLeavingNodeCache: () => { + leavingVNodesCache[key] = vnode + }, + unsetLeavingNodeCache: () => { + if (leavingVNodesCache[key] === vnode) { + delete leavingVNodesCache[key] + } + }, + earlyRemove: () => { + const leavingVNode = leavingVNodesCache[key] + if ( + leavingVNode && + isSameVNodeType(vnode, leavingVNode) && + (leavingVNode.el as TransitionElement)[leaveCbKey] + ) { + // force early removal (not cancelled) + ;(leavingVNode.el as TransitionElement)[leaveCbKey]!() + } + }, + cloneHooks: vnode => { + const hooks = resolveTransitionHooks( + vnode, + props, + state, + instance, + postClone, + ) + if (postClone) postClone(hooks) + return hooks + }, + } + + return baseResolveTransitionHooks(context, props, state, instance) +} + +export function baseResolveTransitionHooks( + context: TransitionHooksContext, + props: BaseTransitionProps, + state: TransitionState, + instance: GenericComponentInstance, +): TransitionHooks { + const { + setLeavingNodeCache, + unsetLeavingNodeCache, + earlyRemove, + cloneHooks, + } = context + const { appear, mode, @@ -345,8 +403,6 @@ export function resolveTransitionHooks( onAfterAppear, onAppearCancelled, } = props - const key = String(vnode.key) - const leavingVNodesCache = getLeavingNodesForType(state, vnode) const callHook: TransitionHookCaller = (hook, args) => { hook && @@ -388,16 +444,7 @@ export function resolveTransitionHooks( el[leaveCbKey](true /* cancelled */) } // for toggled element with same key (v-if) - const leavingVNode = leavingVNodesCache[key] - if ( - leavingVNode && - isSameVNodeType(vnode, leavingVNode) && - // TODO refactor - ((leavingVNode.el || leavingVNode) as TransitionElement)[leaveCbKey] - ) { - // force early removal (not cancelled) - ;((leavingVNode.el || leavingVNode) as TransitionElement)[leaveCbKey]!() - } + earlyRemove() callHook(hook, [el]) }, @@ -436,7 +483,7 @@ export function resolveTransitionHooks( }, leave(el, remove) { - const key = String(vnode.key) + // const key = String(vnode.key) if (el[enterCbKey]) { el[enterCbKey](true /* cancelled */) } @@ -455,11 +502,9 @@ export function resolveTransitionHooks( callHook(onAfterLeave, [el]) } el[leaveCbKey] = undefined - if (leavingVNodesCache[key] === vnode) { - delete leavingVNodesCache[key] - } + unsetLeavingNodeCache() }) - leavingVNodesCache[key] = vnode + setLeavingNodeCache() if (onLeave) { callAsyncHook(onLeave, [el, done]) } else { @@ -467,16 +512,8 @@ export function resolveTransitionHooks( } }, - clone(vnode) { - const hooks = resolveTransitionHooks( - vnode, - props, - state, - instance, - postClone, - ) - if (postClone) postClone(hooks) - return hooks + clone(node) { + return cloneHooks(node) }, } diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 51f42562ee..9da2b2cba4 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -150,8 +150,10 @@ export { registerRuntimeCompiler, isRuntimeOnly } from './component' export { useTransitionState, resolveTransitionHooks, + baseResolveTransitionHooks, setTransitionHooks, getTransitionRawChildren, + leaveCbKey, } from './components/BaseTransition' export { initCustomFormatter } from './customFormatter' @@ -335,6 +337,8 @@ export type { SuspenseBoundary } from './components/Suspense' export type { TransitionState, TransitionHooks, + TransitionHooksContext, + TransitionElement, } from './components/BaseTransition' export type { AsyncComponentOptions, diff --git a/packages/runtime-vapor/src/components/Transition.ts b/packages/runtime-vapor/src/components/Transition.ts index 00cf52414e..9b9410234b 100644 --- a/packages/runtime-vapor/src/components/Transition.ts +++ b/packages/runtime-vapor/src/components/Transition.ts @@ -1,10 +1,15 @@ import { + type GenericComponentInstance, + type TransitionElement, type TransitionHooks, + type TransitionHooksContext, type TransitionProps, + type TransitionState, type VaporTransitionInterface, + baseResolveTransitionHooks, currentInstance, + leaveCbKey, registerVaporTransition, - resolveTransitionHooks, useTransitionState, } from '@vue/runtime-dom' import type { Block } from '../block' @@ -64,6 +69,59 @@ export const vaporTransitionImpl: VaporTransitionInterface = { }, } +function resolveTransitionHooks( + block: Block & { key: string }, + props: TransitionProps, + state: TransitionState, + instance: GenericComponentInstance, + postClone?: (hooks: TransitionHooks) => void, +): TransitionHooks { + const key = String(block.key) + const leavingNodeCache = getLeavingNodesForBlock(state, block) + const context: TransitionHooksContext = { + setLeavingNodeCache: () => { + leavingNodeCache[key] = block + }, + unsetLeavingNodeCache: () => { + if (leavingNodeCache[key] === block) { + delete leavingNodeCache[key] + } + }, + earlyRemove: () => { + const leavingNode = leavingNodeCache[key] + if (leavingNode && (leavingNode as TransitionElement)[leaveCbKey]) { + // force early removal (not cancelled) + ;(leavingNode as TransitionElement)[leaveCbKey]!() + } + }, + cloneHooks: block => { + const hooks = resolveTransitionHooks( + block, + props, + state, + instance, + postClone, + ) + if (postClone) postClone(hooks) + return hooks + }, + } + return baseResolveTransitionHooks(context, props, state, instance) +} + +function getLeavingNodesForBlock( + state: TransitionState, + block: Block, +): Record { + const { leavingVNodes } = state + let leavingNodesCache = leavingVNodes.get(block)! + if (!leavingNodesCache) { + leavingNodesCache = Object.create(null) + leavingVNodes.set(block, leavingNodesCache) + } + return leavingNodesCache +} + function setTransitionHooks(block: Block, hooks: TransitionHooks) { if (isVaporComponent(block)) { setTransitionHooks(block.block, hooks)