From: daiwei Date: Mon, 3 Mar 2025 13:58:09 +0000 (+0800) Subject: wip: save X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1e7905408a873aac496b57772365fdd843f1438e;p=thirdparty%2Fvuejs%2Fcore.git wip: save --- diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index c59fd7338b..7df3d349bf 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -320,8 +320,8 @@ function getLeavingNodesForType( } export interface TransitionHooksContext { - setLeavingNodeCache: () => void - unsetLeavingNodeCache: () => void + setLeavingNodeCache: (node: any) => void + unsetLeavingNodeCache: (node: any) => void earlyRemove: () => void cloneHooks: (node: any) => TransitionHooks } @@ -502,9 +502,9 @@ export function baseResolveTransitionHooks( callHook(onAfterLeave, [el]) } el[leaveCbKey] = undefined - unsetLeavingNodeCache() + unsetLeavingNodeCache(el) }) - setLeavingNodeCache() + setLeavingNodeCache(el) if (onLeave) { callAsyncHook(onLeave, [el, done]) } else { diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 9da2b2cba4..596c31e588 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -564,4 +564,4 @@ export { initFeatureFlags } from './featureFlags' /** * @internal */ -export { applyTransitionEnter, applyTransitionLeave } from './renderer' +export { performTransitionEnter, performTransitionLeave } from './renderer' diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index fc3664de8c..5750bc1689 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -732,7 +732,7 @@ function baseCreateRenderer( // #1583 For inside suspense + suspense not resolved case, enter hook should call when suspense resolved // #1689 For inside suspense + suspense resolved case, just call it if (transition) { - applyTransitionEnter( + performTransitionEnter( el, transition, () => hostInsert(el, container, anchor), @@ -2116,7 +2116,7 @@ function baseCreateRenderer( transition if (needTransition) { if (moveType === MoveType.ENTER) { - applyTransitionEnter( + performTransitionEnter( el!, transition, () => hostInsert(el!, container, anchor), @@ -2297,7 +2297,7 @@ function baseCreateRenderer( } if (transition) { - applyTransitionLeave( + performTransitionLeave( el!, transition, () => hostRemove(el!), @@ -2622,7 +2622,7 @@ export function invalidateMount(hooks: LifecycleHook | undefined): void { } } -export function applyTransitionEnter( +export function performTransitionEnter( el: RendererElement, transition: TransitionHooks, insert: () => void, @@ -2637,7 +2637,7 @@ export function applyTransitionEnter( } } -export function applyTransitionLeave( +export function performTransitionLeave( el: RendererElement, transition: TransitionHooks, remove: () => void, diff --git a/packages/runtime-vapor/src/block.ts b/packages/runtime-vapor/src/block.ts index 8b62dad130..d3019b80f0 100644 --- a/packages/runtime-vapor/src/block.ts +++ b/packages/runtime-vapor/src/block.ts @@ -9,9 +9,15 @@ import { createComment, createTextNode } from './dom/node' import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity' import { type TransitionHooks, - applyTransitionEnter, - applyTransitionLeave, + type TransitionProps, + type TransitionState, + performTransitionEnter, + performTransitionLeave, } from '@vue/runtime-dom' +import { + applyTransitionEnterHooks, + applyTransitionLeaveHooks, +} from './components/Transition' export type Block = ( | Node @@ -22,13 +28,14 @@ export type Block = ( ) & TransitionBlock +export interface VaporTransitionHooks extends TransitionHooks { + state?: TransitionState + props?: TransitionProps +} + export type TransitionBlock = { key?: any - transition?: TransitionHooks - applyTransitionLeavingHooks?: ( - block: Block, - afterLeaveCb: () => void, - ) => TransitionHooks | undefined + transition?: VaporTransitionHooks } export type BlockFn = (...args: any[]) => Block @@ -38,11 +45,7 @@ export class VaporFragment { anchor?: Node insert?: (parent: ParentNode, anchor: Node | null) => void remove?: (parent?: ParentNode) => void - transition?: TransitionHooks - applyTransitionLeavingHooks?: ( - block: Block, - afterLeaveCb: () => void, - ) => TransitionHooks | undefined + transitionChild?: TransitionBlock | undefined constructor(nodes: Block) { this.nodes = nodes @@ -54,6 +57,7 @@ export class DynamicFragment extends VaporFragment { scope: EffectScope | undefined current?: BlockFn fallback?: BlockFn + transitionChild?: Block constructor(anchorLabel?: string) { super([]) @@ -72,9 +76,18 @@ export class DynamicFragment extends VaporFragment { const renderBranch = () => { if (render) { + const transition = this.transition this.scope = new EffectScope() this.nodes = this.scope.run(render) || [] - if (parent) insert(this.nodes, parent, this.anchor, this.transition) + if (transition) { + this.transitionChild = applyTransitionEnterHooks( + this.nodes, + transition.state!, + transition.props!, + transition, + ) + } + if (parent) insert(this.nodes, parent, this.anchor) } else { this.scope = undefined this.nodes = [] @@ -86,32 +99,39 @@ export class DynamicFragment extends VaporFragment { this.scope.stop() const mode = this.transition && this.transition.mode if (mode) { - const transition = this.applyTransitionLeavingHooks!( + applyTransitionLeaveHooks( this.nodes, + this.transition!.state!, + this.transition!.props!, renderBranch, + this.transition, ) - parent && remove(this.nodes, parent, transition) + parent && remove(this.nodes, parent) if (mode === 'out-in') { resetTracking() return } } else { - parent && remove(this.nodes, parent, this.transition) + parent && remove(this.nodes, parent) } } renderBranch() if (this.fallback && !isValidBlock(this.nodes)) { - parent && remove(this.nodes, parent, this.transition) + parent && remove(this.nodes, parent) this.nodes = (this.scope || (this.scope = new EffectScope())).run(this.fallback) || [] - parent && insert(this.nodes, parent, this.anchor, this.transition) + parent && insert(this.nodes, parent, this.anchor) } resetTracking() } + + get transition(): VaporTransitionHooks | undefined { + return this.transitionChild && this.transitionChild.transition + } } export function isFragment(val: NonNullable): val is VaporFragment { @@ -144,16 +164,16 @@ export function insert( block: Block, parent: ParentNode, anchor: Node | null | 0 = null, // 0 means prepend - transition: TransitionHooks | undefined = block.transition, parentSuspense?: any, // TODO Suspense ): void { anchor = anchor === 0 ? parent.firstChild : anchor if (block instanceof Node) { // don't apply transition on text or comment nodes - if (transition && block instanceof Element) { - applyTransitionEnter( + if (block.transition && block instanceof Element) { + performTransitionEnter( block, - transition, + // @ts-expect-error + block.transition, () => parent.insertBefore(block, anchor), parentSuspense, ) @@ -161,7 +181,7 @@ export function insert( parent.insertBefore(block, anchor) } } else if (isVaporComponent(block)) { - mountComponent(block, parent, anchor, transition) + mountComponent(block, parent, anchor) } else if (isArray(block)) { for (let i = 0; i < block.length; i++) { insert(block[i], parent, anchor) @@ -171,7 +191,7 @@ export function insert( if (block.insert) { block.insert(parent, anchor) } else { - insert(block.nodes, parent, anchor, block.transition) + insert(block.nodes, parent, anchor, parentSuspense) } if (block.anchor) insert(block.anchor, parent, anchor) } @@ -182,23 +202,20 @@ export function prepend(parent: ParentNode, ...blocks: Block[]): void { while (i--) insert(blocks[i], parent, 0) } -export function remove( - block: Block, - parent?: ParentNode, - transition: TransitionHooks | undefined = block.transition, -): void { +export function remove(block: Block, parent?: ParentNode): void { if (block instanceof Node) { - if (transition && block instanceof Element) { - applyTransitionLeave( + if (block.transition && block instanceof Element) { + performTransitionLeave( block, - transition, + // @ts-expect-error + block.transition, () => parent && parent.removeChild(block), ) } else { parent && parent.removeChild(block) } } else if (isVaporComponent(block)) { - unmountComponent(block, parent, transition) + unmountComponent(block, parent) } else if (isArray(block)) { for (let i = 0; i < block.length; i++) { remove(block[i], parent) @@ -208,7 +225,7 @@ export function remove( if (block.remove) { block.remove(parent) } else { - remove(block.nodes, parent, block.transition) + remove(block.nodes, parent) } if (block.anchor) remove(block.anchor, parent) if ((block as DynamicFragment).scope) { diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index 2c448bda24..3c39612bb8 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -11,7 +11,6 @@ import { type NormalizedPropsOptions, type ObjectEmitsOptions, type SuspenseBoundary, - type TransitionHooks, callWithErrorHandling, currentInstance, endMeasure, @@ -476,18 +475,17 @@ export function mountComponent( instance: VaporComponentInstance, parent: ParentNode, anchor?: Node | null | 0, - transition?: TransitionHooks, ): void { if (__DEV__) { startMeasure(instance, `mount`) } if (!instance.isMounted) { if (instance.bm) invokeArrayFns(instance.bm) - insert(instance.block, parent, anchor, transition) + insert(instance.block, parent, anchor) if (instance.m) queuePostFlushCb(() => invokeArrayFns(instance.m!)) instance.isMounted = true } else { - insert(instance.block, parent, anchor, transition) + insert(instance.block, parent, anchor) } if (__DEV__) { endMeasure(instance, `mount`) @@ -497,7 +495,6 @@ export function mountComponent( export function unmountComponent( instance: VaporComponentInstance, parentNode?: ParentNode, - transition?: TransitionHooks, ): void { if (instance.isMounted && !instance.isUnmounted) { if (__DEV__ && instance.type.__hmrId) { @@ -516,7 +513,7 @@ export function unmountComponent( } if (parentNode) { - remove(instance.block, parentNode, transition) + remove(instance.block, parentNode) } } diff --git a/packages/runtime-vapor/src/components/Transition.ts b/packages/runtime-vapor/src/components/Transition.ts index 28c6cd0a7f..cae810067b 100644 --- a/packages/runtime-vapor/src/components/Transition.ts +++ b/packages/runtime-vapor/src/components/Transition.ts @@ -13,7 +13,7 @@ import { useTransitionState, warn, } from '@vue/runtime-dom' -import type { Block } from '../block' +import { type Block, type VaporTransitionHooks, isFragment } from '../block' import { isVaporComponent } from '../component' export const vaporTransitionImpl: VaporTransitionInterface = { @@ -24,19 +24,6 @@ export const vaporTransitionImpl: VaporTransitionInterface = { const children = slots.default && slots.default() if (!children) return - const child = findElementChild(children) - if (!child) return - - const state = useTransitionState() - let enterHooks = resolveTransitionHooks( - child as any, - props, - state, - currentInstance!, - hooks => (enterHooks = hooks), - ) - setTransitionHooks(child, enterHooks) - const { mode } = props if ( __DEV__ && @@ -48,57 +35,19 @@ export const vaporTransitionImpl: VaporTransitionInterface = { warn(`invalid mode: ${mode}`) } - child.applyTransitionLeavingHooks = ( - block: Block, - afterLeaveCb: () => void, - ) => { - const leavingBlock = findElementChild(block) - if (!leavingBlock) return undefined - - let leavingHooks = resolveTransitionHooks( - leavingBlock as any, - props, - state, - currentInstance!, - ) - setTransitionHooks(leavingBlock, leavingHooks) - - if (mode === 'out-in') { - state.isLeaving = true - leavingHooks.afterLeave = () => { - state.isLeaving = false - afterLeaveCb() - delete leavingHooks.afterLeave - } - } else if (mode === 'in-out') { - leavingHooks.delayLeave = ( - block: TransitionElement, - earlyRemove, - delayedLeave, - ) => { - const leavingNodeCache = getLeavingNodesForBlock(state, leavingBlock) - leavingNodeCache[String(leavingBlock.key)] = leavingBlock - // early removal callback - block[leaveCbKey] = () => { - earlyRemove() - block[leaveCbKey] = undefined - delete enterHooks.delayedLeave - } - enterHooks.delayedLeave = () => { - delayedLeave() - delete enterHooks.delayedLeave - } - } - } - return leavingHooks - } + applyTransitionEnterHooks( + children, + useTransitionState(), + props, + undefined, + false, + ) return children }, } const getTransitionHooksContext = ( - leavingNodeCache: Record, key: string, block: Block, props: TransitionProps, @@ -107,15 +56,18 @@ const getTransitionHooksContext = ( postClone: ((hooks: TransitionHooks) => void) | undefined, ) => { const context: TransitionHooksContext = { - setLeavingNodeCache: () => { - leavingNodeCache[key] = block + setLeavingNodeCache: el => { + const leavingNodeCache = getLeavingNodesForBlock(state, block) + leavingNodeCache[key] = el }, - unsetLeavingNodeCache: () => { - if (leavingNodeCache[key] === block) { + unsetLeavingNodeCache: el => { + const leavingNodeCache = getLeavingNodesForBlock(state, block) + if (leavingNodeCache[key] === el) { delete leavingNodeCache[key] } }, earlyRemove: () => { + const leavingNodeCache = getLeavingNodesForBlock(state, block) const leavingNode = leavingNodeCache[key] if (leavingNode && (leavingNode as TransitionElement)[leaveCbKey]) { // force early removal (not cancelled) @@ -143,11 +95,9 @@ function resolveTransitionHooks( state: TransitionState, instance: GenericComponentInstance, postClone?: (hooks: TransitionHooks) => void, -): TransitionHooks { +): VaporTransitionHooks { const key = String(block.key) - const leavingNodeCache = getLeavingNodesForBlock(state, block) const context = getTransitionHooksContext( - leavingNodeCache, key, block, props, @@ -155,7 +105,15 @@ function resolveTransitionHooks( instance, postClone, ) - return baseResolveTransitionHooks(context, props, state, instance) + const hooks: VaporTransitionHooks = baseResolveTransitionHooks( + context, + props, + state, + instance, + ) + hooks.state = state + hooks.props = props + return hooks } function getLeavingNodesForBlock( @@ -171,15 +129,96 @@ function getLeavingNodesForBlock( return leavingNodesCache } -function setTransitionHooks(block: Block, hooks: TransitionHooks) { - block.transition = hooks +function setTransitionHooks(block: Block, hooks: VaporTransitionHooks) { + if (!isFragment(block)) { + block.transition = hooks + } +} + +export function applyTransitionEnterHooks( + block: Block, + state: TransitionState, + props: TransitionProps, + enterHooks?: VaporTransitionHooks, + clone: boolean = true, +): Block | undefined { + const child = findElementChild(block) + if (child) { + if (!enterHooks) { + enterHooks = resolveTransitionHooks( + child, + props, + state, + currentInstance!, + hooks => (enterHooks = hooks), + ) + } + + setTransitionHooks( + child, + clone ? enterHooks.clone(child as any) : enterHooks, + ) + + if (isFragment(block)) { + block.transitionChild = child + } + } + return child +} + +export function applyTransitionLeaveHooks( + block: Block, + state: TransitionState, + props: TransitionProps, + afterLeaveCb: () => void, + enterHooks: TransitionHooks, +): void { + const leavingBlock = findElementChild(block) + if (!leavingBlock) return undefined + + let leavingHooks = resolveTransitionHooks( + leavingBlock, + props, + state, + currentInstance!, + ) + setTransitionHooks(leavingBlock, leavingHooks) + + const { mode } = props + if (mode === 'out-in') { + state.isLeaving = true + leavingHooks.afterLeave = () => { + state.isLeaving = false + afterLeaveCb() + delete leavingHooks.afterLeave + } + } else if (mode === 'in-out') { + leavingHooks.delayLeave = ( + block: TransitionElement, + earlyRemove, + delayedLeave, + ) => { + const leavingNodeCache = getLeavingNodesForBlock(state, leavingBlock) + leavingNodeCache[String(leavingBlock.key)] = leavingBlock + // early removal callback + block[leaveCbKey] = () => { + earlyRemove() + block[leaveCbKey] = undefined + delete enterHooks.delayedLeave + } + enterHooks.delayedLeave = () => { + delayedLeave() + delete enterHooks.delayedLeave + } + } + } } -function findElementChild(block: Block): Block | undefined { +export function findElementChild(block: Block): Block | undefined { let child: Block | undefined - // transition can only be applied on Element child - if (block instanceof Element) { - child = block + if (block instanceof Node) { + // transition can only be applied on Element child + if (block instanceof Element) child = block } else if (isVaporComponent(block)) { child = findElementChild(block.block) } else if (Array.isArray(block)) { @@ -203,9 +242,7 @@ function findElementChild(block: Block): Block | undefined { } } else { // fragment - // store transition hooks on fragment itself, so it can apply to both - // previous and new branch during updates. - child = block + child = findElementChild(block.nodes) } if (__DEV__ && !child) {