The Transition component works by adding and removing animation classes. The Transition component works by adding and removing animation classes.

Vue provides a wrapper component for Transition. You can add an entry/exit transition to any element or component in the following cases:

  • Conditional Rendering (using V-if)
  • Conditional presentation (using V-show)
  • Dynamic components
  • Component root node

How does Transition sniff if CSS transitions or animations are applied

In conditional rendering, when Vue is mountElement in patch function, the following method is used to sniff transition.

// parentSuspense is related to Suspense components and is not considered for the time being
 const monuntElement = function (vnode, / /...). {
   const { transition } = vnode
   // ...
   // Determine whether to use transition
   constneedCallTransitionHooks = (! parentSuspense || (parentSuspense && ! parentSuspense.pendingBranch)) && transition && ! transition.persisted// Initialize the animation with the beforEnter hook function
   if(needCallTransitionHooks) { transition! .beforeEnter(el) }// ...
 }
 
 
Copy the code

Transition is resolved from the internal hook function by resolveTransitionHooks and added to the transition property of vNode by setTransitionHooks

// BaseTransition.ts
const BaseTransitionImpl = {
  setup (props, { slots }) {
    return (() = > {
      // ...
      // The transition hook is attached to the vnode as vNode. transition
      const enterHooks = resolveTransitionHooks(
        innerChild,
        rawProps,
        state,
        instance
      )
      setTransitionHooks(child, enterHooks)
      // ...}}})function setTransitionHooks (vnode, hooks) {
  if (vnode.shapeFlag & ShapeFlags.COMPONENT && vnode.component) {
    setTransitionHooks(vnode.component.subTree, hooks)
  } else if(__FEATURE_SUSPENSE__ && vnode.shapeFlag & ShapeFlags.SUSPENSE) { vnode.ssContent! .transition = hooks.clone(vnode.ssContent!) vnode.ssFallback! .transition = hooks.clone(vnode.ssFallback!) }else {
    vnode.transition = hooks / / set the hooks}}Copy the code

ResolveTransitionHooks () => The TransitionHooks method provides methods such as Enter and leave to handle hook functions

interface TransitionHooks {
  mode: BaseTransitionProps['mode']
  persisted: boolean
  beforeEnter(el: HostElement): void
  enter(el: HostElement): void
  leave(el: HostElement, remove: () = > void) :void
  clone(vnode: VNode): TransitionHooks<HostElement>
  // optionalafterLeave? () :voiddelayLeave? ( el: HostElement,earlyRemove: () = > void.delayedLeave: () = > void) :voiddelayedLeave? () :void
}
Copy the code

How is the Transition class name added at the right time

When TransitionHooks are called, they trigger the functions generated by the resolveTransitionProps method to add the transition class name when appropriate, similar to our v-enter-active, v-from-active… , and finally ends the transition animation with the whenTransitionEnds method

export const Transition = (props, { slots }) = > 
  h(BaseTransition, resolveTransitionProps(props), slots)
Copy the code
@runtime-dom/src/components/Transition
// You can check it by yourself
function resolveTransitionProps() {
  // ...
  // How to add animation Class with Enter example
  const makeEnterHook = (isAppear) = > {
    return (el, done) = > {
      const hook = isAppear ? onAppear : onEnter;
      const resolve = () = > finishEnter(el, isAppear, done);
      hook && hook(el, resolve); // Calls the hook function passed in when used
      nextFrame(() = > {
          removeTransitionClass(el, isAppear ? appearFromClass : enterFromClass);
          addTransitionClass(el, isAppear ? appearToClass : enterToClass);
          if(! (hook && hook.length >1)) { whenTransitionEnds(el, type, enterDuration, resolve); }}); };return {
    // ...
    onEnter: makeEnterHook(false)}}; }Copy the code

Add/remove the transitionClass method

function addTransitionClass(el, cls) {
  cls.split(/\s+/).forEach(c= > c && el.classList.add(c));
  (el._vtc ||
      (el._vtc = new Set())).add(cls);
}
function removeTransitionClass(el, cls) {
  cls.split(/\s+/).forEach(c= > c && el.classList.remove(c));
  const { _vtc } = el;
  if (_vtc) {
      _vtc.delete(cls);
      if(! _vtc.size) { el._vtc =undefined; }}}Copy the code

The vShow conditional display triggers the Transition hook function in the vShow instruction

export const vShow = {
  beforeMount(el, { value }, { transition }) {
    el._vod = el.style.display === 'none' ? ' ' : el.style.display
    if (transition && value) {
      transition.beforeEnter(el) // before
    } else {
      setDisplay(el, value)
    }
  },
  mounted(el, { value }, { transition }) {
    if (transition && value) {
      transition.enter(el) // enter}},updated(el, { value, oldValue }, { transition }) {
    // update
    if(transition && value ! == oldValue) {if (value) {
        transition.beforeEnter(el)
        setDisplay(el, true)
        transition.enter(el)
      } else {
        transition.leave(el, () = > {
          setDisplay(el, false)}}}else {
      setDisplay(el, value)
    }
  },
  beforeUnmount(el, { value }) {
    setDisplay(el, value)
  }
}
Copy the code

Unload hook functions and TransitionClass

When the component reaches the unmount method, the remove method is called to uninstall the transition animation of the component. VShow is performed in the update command.

const remove = vnode= > {
  const { type, el, anchor, transition } = vnode;
  // ...
  const performRemove = () = > {
      hostRemove(el);
      if (transition && !transition.persisted && transition.afterLeave) {
          transition.afterLeave();
      }
  };
  if (vnode.shapeFlag & 1 /* ELEMENT */&& transition && ! transition.persisted) {const { leave, delayLeave } = transition; / / add leave - the transition - class
      const performLeave = () = > leave(el, performRemove);
      if (delayLeave) {
          delayLeave(vnode.el, performRemove, performLeave);
      }
      else{ performLeave(); }}else{ performRemove(); }};Copy the code

conclusion

Transition itself does not render a DOM element and does not appear in the parent component chain. Instead, it renders a child node. The Transition code is very clever, and the childVnode Transition property handles the entry/exit of the animation. It is really interesting to learn and think about.

The Transition component is very rich. Personal understanding is limited, I hope to help you. If there are any mistakes, please correct them.