]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: save
authordaiwei <daiwei521@126.com>
Mon, 3 Mar 2025 13:58:09 +0000 (21:58 +0800)
committerdaiwei <daiwei521@126.com>
Mon, 3 Mar 2025 14:07:46 +0000 (22:07 +0800)
packages/runtime-core/src/components/BaseTransition.ts
packages/runtime-core/src/index.ts
packages/runtime-core/src/renderer.ts
packages/runtime-vapor/src/block.ts
packages/runtime-vapor/src/component.ts
packages/runtime-vapor/src/components/Transition.ts

index c59fd7338b1211efa665d534d7920f944b8976d1..7df3d349bf51c2ba49f837e08e115e08b272f779 100644 (file)
@@ -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 {
index 9da2b2cba4ba92cd10ef7bc965c42d82fe526101..596c31e588380a2b6a2dc0e169be2ca8c8fcb46c 100644 (file)
@@ -564,4 +564,4 @@ export { initFeatureFlags } from './featureFlags'
 /**
  * @internal
  */
-export { applyTransitionEnter, applyTransitionLeave } from './renderer'
+export { performTransitionEnter, performTransitionLeave } from './renderer'
index fc3664de8c7812d4598008e8b2f7bbc368756f4f..5750bc168918680dfe101beb5d22394dc59ed632 100644 (file)
@@ -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,
index 8b62dad1308060303e7372316cfde18469d7735e..d3019b80f0f57849547ace901d0d01e96af0d783 100644 (file)
@@ -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<unknown>): 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) {
index 2c448bda2467a97937291b0fd531c4eefca175f0..3c39612bb89d77ae185f6a4b278adec5377a5122 100644 (file)
@@ -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)
   }
 }
 
index 28c6cd0a7f0ed505bec365adfbe5ebbd79b623eb..cae810067b0722b344af98c3173a58061f8d3e89 100644 (file)
@@ -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 <transition> 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<string, Block>,
   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) {