src/platforms/web/runtime/modules/transition.ts TYPESCRIPT 342 lines View on github.com → Search inside
1import { inBrowser, isIE9, warn } from 'core/util/index'2import { mergeVNodeHook } from 'core/vdom/helpers/index'3import { activeInstance } from 'core/instance/lifecycle'45import {6  once,7  isDef,8  isUndef,9  isObject,10  toNumber,11  isFunction12} from 'shared/util'1314import {15  nextFrame,16  resolveTransition,17  whenTransitionEnds,18  addTransitionClass,19  removeTransitionClass20} from 'web/runtime/transition-util'2122import type { VNodeWithData } from 'types/vnode'23import VNode from 'core/vdom/vnode'2425export function enter(vnode: VNodeWithData, toggleDisplay?: () => void) {26  const el: any = vnode.elm2728  // call leave callback now29  if (isDef(el._leaveCb)) {30    el._leaveCb.cancelled = true31    el._leaveCb()32  }3334  const data = resolveTransition(vnode.data.transition)35  if (isUndef(data)) {36    return37  }3839  /* istanbul ignore if */40  if (isDef(el._enterCb) || el.nodeType !== 1) {41    return42  }4344  const {45    css,46    type,47    enterClass,48    enterToClass,49    enterActiveClass,50    appearClass,51    appearToClass,52    appearActiveClass,53    beforeEnter,54    enter,55    afterEnter,56    enterCancelled,57    beforeAppear,58    appear,59    afterAppear,60    appearCancelled,61    duration62  } = data6364  // activeInstance will always be the <transition> component managing this65  // transition. One edge case to check is when the <transition> is placed66  // as the root node of a child component. In that case we need to check67  // <transition>'s parent for appear check.68  let context = activeInstance69  let transitionNode = activeInstance.$vnode70  while (transitionNode && transitionNode.parent) {71    context = transitionNode.context72    transitionNode = transitionNode.parent73  }7475  const isAppear = !context._isMounted || !vnode.isRootInsert7677  if (isAppear && !appear && appear !== '') {78    return79  }8081  const startClass = isAppear && appearClass ? appearClass : enterClass82  const activeClass =83    isAppear && appearActiveClass ? appearActiveClass : enterActiveClass84  const toClass = isAppear && appearToClass ? appearToClass : enterToClass8586  const beforeEnterHook = isAppear ? beforeAppear || beforeEnter : beforeEnter87  const enterHook = isAppear ? (isFunction(appear) ? appear : enter) : enter88  const afterEnterHook = isAppear ? afterAppear || afterEnter : afterEnter89  const enterCancelledHook = isAppear90    ? appearCancelled || enterCancelled91    : enterCancelled9293  const explicitEnterDuration: any = toNumber(94    isObject(duration) ? duration.enter : duration95  )9697  if (__DEV__ && explicitEnterDuration != null) {98    checkDuration(explicitEnterDuration, 'enter', vnode)99  }100101  const expectsCSS = css !== false && !isIE9102  const userWantsControl = getHookArgumentsLength(enterHook)103104  const cb = (el._enterCb = once(() => {105    if (expectsCSS) {106      removeTransitionClass(el, toClass)107      removeTransitionClass(el, activeClass)108    }109    // @ts-expect-error110    if (cb.cancelled) {111      if (expectsCSS) {112        removeTransitionClass(el, startClass)113      }114      enterCancelledHook && enterCancelledHook(el)115    } else {116      afterEnterHook && afterEnterHook(el)117    }118    el._enterCb = null119  }))120121  if (!vnode.data.show) {122    // remove pending leave element on enter by injecting an insert hook123    mergeVNodeHook(vnode, 'insert', () => {124      const parent = el.parentNode125      const pendingNode =126        parent && parent._pending && parent._pending[vnode.key!]127      if (128        pendingNode &&129        pendingNode.tag === vnode.tag &&130        pendingNode.elm._leaveCb131      ) {132        pendingNode.elm._leaveCb()133      }134      enterHook && enterHook(el, cb)135    })136  }137138  // start enter transition139  beforeEnterHook && beforeEnterHook(el)140  if (expectsCSS) {141    addTransitionClass(el, startClass)142    addTransitionClass(el, activeClass)143    nextFrame(() => {144      removeTransitionClass(el, startClass)145      // @ts-expect-error146      if (!cb.cancelled) {147        addTransitionClass(el, toClass)148        if (!userWantsControl) {149          if (isValidDuration(explicitEnterDuration)) {150            setTimeout(cb, explicitEnterDuration)151          } else {152            whenTransitionEnds(el, type, cb)153          }154        }155      }156    })157  }158159  if (vnode.data.show) {160    toggleDisplay && toggleDisplay()161    enterHook && enterHook(el, cb)162  }163164  if (!expectsCSS && !userWantsControl) {165    cb()166  }167}168169export function leave(vnode: VNodeWithData, rm: Function) {170  const el: any = vnode.elm171172  // call enter callback now173  if (isDef(el._enterCb)) {174    el._enterCb.cancelled = true175    el._enterCb()176  }177178  const data = resolveTransition(vnode.data.transition)179  if (isUndef(data) || el.nodeType !== 1) {180    return rm()181  }182183  /* istanbul ignore if */184  if (isDef(el._leaveCb)) {185    return186  }187188  const {189    css,190    type,191    leaveClass,192    leaveToClass,193    leaveActiveClass,194    beforeLeave,195    leave,196    afterLeave,197    leaveCancelled,198    delayLeave,199    duration200  } = data201202  const expectsCSS = css !== false && !isIE9203  const userWantsControl = getHookArgumentsLength(leave)204205  const explicitLeaveDuration: any = toNumber(206    isObject(duration) ? duration.leave : duration207  )208209  if (__DEV__ && isDef(explicitLeaveDuration)) {210    checkDuration(explicitLeaveDuration, 'leave', vnode)211  }212213  const cb = (el._leaveCb = once(() => {214    if (el.parentNode && el.parentNode._pending) {215      el.parentNode._pending[vnode.key!] = null216    }217    if (expectsCSS) {218      removeTransitionClass(el, leaveToClass)219      removeTransitionClass(el, leaveActiveClass)220    }221    // @ts-expect-error222    if (cb.cancelled) {223      if (expectsCSS) {224        removeTransitionClass(el, leaveClass)225      }226      leaveCancelled && leaveCancelled(el)227    } else {228      rm()229      afterLeave && afterLeave(el)230    }231    el._leaveCb = null232  }))233234  if (delayLeave) {235    delayLeave(performLeave)236  } else {237    performLeave()238  }239240  function performLeave() {241    // the delayed leave may have already been cancelled242    // @ts-expect-error243    if (cb.cancelled) {244      return245    }246    // record leaving element247    if (!vnode.data.show && el.parentNode) {248      ;(el.parentNode._pending || (el.parentNode._pending = {}))[vnode.key!] =249        vnode250    }251    beforeLeave && beforeLeave(el)252    if (expectsCSS) {253      addTransitionClass(el, leaveClass)254      addTransitionClass(el, leaveActiveClass)255      nextFrame(() => {256        removeTransitionClass(el, leaveClass)257        // @ts-expect-error258        if (!cb.cancelled) {259          addTransitionClass(el, leaveToClass)260          if (!userWantsControl) {261            if (isValidDuration(explicitLeaveDuration)) {262              setTimeout(cb, explicitLeaveDuration)263            } else {264              whenTransitionEnds(el, type, cb)265            }266          }267        }268      })269    }270    leave && leave(el, cb)271    if (!expectsCSS && !userWantsControl) {272      cb()273    }274  }275}276277// only used in dev mode278function checkDuration(val, name, vnode) {279  if (typeof val !== 'number') {280    warn(281      `<transition> explicit ${name} duration is not a valid number - ` +282        `got ${JSON.stringify(val)}.`,283      vnode.context284    )285  } else if (isNaN(val)) {286    warn(287      `<transition> explicit ${name} duration is NaN - ` +288        'the duration expression might be incorrect.',289      vnode.context290    )291  }292}293294function isValidDuration(val) {295  return typeof val === 'number' && !isNaN(val)296}297298/**299 * Normalize a transition hook's argument length. The hook may be:300 * - a merged hook (invoker) with the original in .fns301 * - a wrapped component method (check ._length)302 * - a plain function (.length)303 */304function getHookArgumentsLength(fn: Function): boolean {305  if (isUndef(fn)) {306    return false307  }308  // @ts-expect-error309  const invokerFns = fn.fns310  if (isDef(invokerFns)) {311    // invoker312    return getHookArgumentsLength(313      Array.isArray(invokerFns) ? invokerFns[0] : invokerFns314    )315  } else {316    // @ts-expect-error317    return (fn._length || fn.length) > 1318  }319}320321function _enter(_: any, vnode: VNodeWithData) {322  if (vnode.data.show !== true) {323    enter(vnode)324  }325}326327export default inBrowser328  ? {329      create: _enter,330      activate: _enter,331      remove(vnode: VNode, rm: Function) {332        /* istanbul ignore else */333        if (vnode.data!.show !== true) {334          // @ts-expect-error335          leave(vnode, rm)336        } else {337          rm()338        }339      }340    }341  : {}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.