From: daiwei Date: Mon, 3 Mar 2025 03:44:57 +0000 (+0800) Subject: wip: save X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=413651d6e6085e38650539f0a871323da452e907;p=thirdparty%2Fvuejs%2Fcore.git wip: save --- diff --git a/packages/runtime-vapor/src/block.ts b/packages/runtime-vapor/src/block.ts index e0748fe879..8b62dad130 100644 --- a/packages/runtime-vapor/src/block.ts +++ b/packages/runtime-vapor/src/block.ts @@ -25,10 +25,10 @@ export type Block = ( export type TransitionBlock = { key?: any transition?: TransitionHooks - applyLeavingHooks?: ( + applyTransitionLeavingHooks?: ( block: Block, afterLeaveCb: () => void, - ) => TransitionHooks + ) => TransitionHooks | undefined } export type BlockFn = (...args: any[]) => Block @@ -39,10 +39,10 @@ export class VaporFragment { insert?: (parent: ParentNode, anchor: Node | null) => void remove?: (parent?: ParentNode) => void transition?: TransitionHooks - applyLeavingHooks?: ( + applyTransitionLeavingHooks?: ( block: Block, afterLeaveCb: () => void, - ) => TransitionHooks + ) => TransitionHooks | undefined constructor(nodes: Block) { this.nodes = nodes @@ -70,7 +70,7 @@ export class DynamicFragment extends VaporFragment { pauseTracking() const parent = this.anchor.parentNode - const renderNewBranch = () => { + const renderBranch = () => { if (render) { this.scope = new EffectScope() this.nodes = this.scope.run(render) || [] @@ -79,14 +79,6 @@ export class DynamicFragment extends VaporFragment { this.scope = undefined this.nodes = [] } - - if (this.fallback && !isValidBlock(this.nodes)) { - parent && remove(this.nodes, parent, this.transition) - this.nodes = - (this.scope || (this.scope = new EffectScope())).run(this.fallback) || - [] - parent && insert(this.nodes, parent, this.anchor, this.transition) - } } // teardown previous branch @@ -94,7 +86,10 @@ export class DynamicFragment extends VaporFragment { this.scope.stop() const mode = this.transition && this.transition.mode if (mode) { - const transition = this.applyLeavingHooks!(this.nodes, renderNewBranch) + const transition = this.applyTransitionLeavingHooks!( + this.nodes, + renderBranch, + ) parent && remove(this.nodes, parent, transition) if (mode === 'out-in') { resetTracking() @@ -105,7 +100,16 @@ export class DynamicFragment extends VaporFragment { } } - renderNewBranch() + renderBranch() + + if (this.fallback && !isValidBlock(this.nodes)) { + parent && remove(this.nodes, parent, this.transition) + this.nodes = + (this.scope || (this.scope = new EffectScope())).run(this.fallback) || + [] + parent && insert(this.nodes, parent, this.anchor, this.transition) + } + resetTracking() } } @@ -145,7 +149,8 @@ export function insert( ): void { anchor = anchor === 0 ? parent.firstChild : anchor if (block instanceof Node) { - if (transition) { + // don't apply transition on text or comment nodes + if (transition && block instanceof Element) { applyTransitionEnter( block, transition, @@ -183,7 +188,7 @@ export function remove( transition: TransitionHooks | undefined = block.transition, ): void { if (block instanceof Node) { - if (transition) { + if (transition && block instanceof Element) { applyTransitionLeave( block, transition, diff --git a/packages/runtime-vapor/src/components/Transition.ts b/packages/runtime-vapor/src/components/Transition.ts index b203db4669..28c6cd0a7f 100644 --- a/packages/runtime-vapor/src/components/Transition.ts +++ b/packages/runtime-vapor/src/components/Transition.ts @@ -11,6 +11,7 @@ import { leaveCbKey, registerVaporTransition, useTransitionState, + warn, } from '@vue/runtime-dom' import type { Block } from '../block' import { isVaporComponent } from '../component' @@ -21,12 +22,10 @@ export const vaporTransitionImpl: VaporTransitionInterface = { slots: { default: () => Block }, ) => { const children = slots.default && slots.default() - if (!children) { - return - } + if (!children) return - // TODO find non-comment node - const child = children + const child = findElementChild(children) + if (!child) return const state = useTransitionState() let enterHooks = resolveTransitionHooks( @@ -39,12 +38,23 @@ export const vaporTransitionImpl: VaporTransitionInterface = { setTransitionHooks(child, enterHooks) const { mode } = props - // TODO check mode + if ( + __DEV__ && + mode && + mode !== 'in-out' && + mode !== 'out-in' && + mode !== 'default' + ) { + warn(`invalid mode: ${mode}`) + } - child.applyLeavingHooks = ( - leavingBlock: Block, + child.applyTransitionLeavingHooks = ( + block: Block, afterLeaveCb: () => void, ) => { + const leavingBlock = findElementChild(block) + if (!leavingBlock) return undefined + let leavingHooks = resolveTransitionHooks( leavingBlock as any, props, @@ -87,15 +97,15 @@ export const vaporTransitionImpl: VaporTransitionInterface = { }, } -function resolveTransitionHooks( +const getTransitionHooksContext = ( + leavingNodeCache: Record, + key: string, block: Block, props: TransitionProps, state: TransitionState, instance: GenericComponentInstance, - postClone?: (hooks: TransitionHooks) => void, -): TransitionHooks { - const key = String(block.key) - const leavingNodeCache = getLeavingNodesForBlock(state, block) + postClone: ((hooks: TransitionHooks) => void) | undefined, +) => { const context: TransitionHooksContext = { setLeavingNodeCache: () => { leavingNodeCache[key] = block @@ -124,6 +134,27 @@ function resolveTransitionHooks( return hooks }, } + return context +} + +function resolveTransitionHooks( + block: Block, + props: TransitionProps, + state: TransitionState, + instance: GenericComponentInstance, + postClone?: (hooks: TransitionHooks) => void, +): TransitionHooks { + const key = String(block.key) + const leavingNodeCache = getLeavingNodesForBlock(state, block) + const context = getTransitionHooksContext( + leavingNodeCache, + key, + block, + props, + state, + instance, + postClone, + ) return baseResolveTransitionHooks(context, props, state, instance) } @@ -141,11 +172,47 @@ function getLeavingNodesForBlock( } function setTransitionHooks(block: Block, hooks: TransitionHooks) { - if (isVaporComponent(block)) { - setTransitionHooks(block.block, hooks) + block.transition = hooks +} + +function findElementChild(block: Block): Block | undefined { + let child: Block | undefined + // 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)) { + child = block[0] + let hasFound = false + for (const c of block) { + const item = findElementChild(c) + if (item instanceof Element) { + if (__DEV__ && hasFound) { + // warn more than one non-comment child + warn( + ' can only be used on a single element or component. ' + + 'Use for lists.', + ) + break + } + child = item + hasFound = true + if (!__DEV__) break + } + } } else { - block.transition = hooks + // fragment + // store transition hooks on fragment itself, so it can apply to both + // previous and new branch during updates. + child = block } + + if (__DEV__ && !child) { + warn('Transition component has no valid child element') + } + + return child } let registered = false