// Replace Transition in Vue's Components method
extend(Vue.options.components,platformComponents)
Copy the code

transition

export default{
  name:'transition'.props:transitionProps,// Transition state related attributes
  abstract:true.render(h){
    // Get the DOM of the transition application
    let children = this.$slots.default
    // If the dom of the application does not exist or is a textNode, no operation is performed
    if(! children){return
    }
    children = children.filter(isNotTextNode)
    if(! children.length){return 
    }
    // Multiple DOM states are changed using transitionGroup, whether mode corresponds to Vue.const rawChild = children[0]
    // Skip transition if the parent element of the current DOM exists
    if(hasParentTransition(rawChild)){
      return rawChild
    }
    // Skip transition if the child of the current DOM is keep-alive
    const child = getRealChild(rawChild)
    if(! child){return rawChild
    }
    if(this._leaving){
      // The current element transitions first
      return placeholder(h,rawChild)
    }
    ...
    const data = (child.data || (child.data = {})).transition = extractTransitionData(this)
    const oldRawChild = this._vnode
    const oldChild = getRealChild(oldRawChild)
    // Determine the transition state change caused by the V-show command
    if(child.data.directives && child.data.directives.some(isVShowDirective)){
      child.data.show = true
    }
    // Compare the node changes before and after
    if(oldChild && oldChild.data && ! isSameChild(child,oldChild) && ! isAsyncPlaceholder(oldChild) && ! (oldChild.componentInstance && oldChild.componentInstance._vnode.isComment)){const oldData = oldChid.data.transition = extend({},data)
      if(mode === 'out-in') {// The current element is advanced transition, after the completion of the new element transition
        this._leaving = true
        mergeVNodeHook(oldData,'afterLeave'.() = > {
          this._leaving = false;
          this.$forceUpdate()
        })
        return placeholder(h,rawChild)
      }else if(mode === 'in-out') {// The new element transitions first, then the current element transitions away
        if(isAsyncPlaceholder(child)){
          return oldRawChild
        }
        let delayedLeave
        const performLeave = () = > {delayedLeave()}
        // Add a hook function to the current dom state
        mergeVNodeHook(data,'afterEnter',performLeave)
        mergeVNodeHook(data,'enterCancelled',performLeave)
        mergeVNodeHook(data,'delayLeave'.leave= > {delayedLeave = leave})
      }
    }
    return rawChild
  }
}
Copy the code

transition-group

export default {
  props,
  beforMount(){
    const update = this._update
    // Before transtionGroup is mounted, override _update to update elements under the group before DOM is updated
    this._update = (vnode,hydrating) = > {
      const restoreActiveInstance = setActiveInstance(this)
      this.__patch__(this._vnode,this.kept,false.true)
      this._vnode = this.kept
      restoreActiveInstance()
      update.call(this,vnode,hydrating)
    }
  },
  render(h){
    const tag = this.tag || this.$vnode.data.tag || 'span'
    const map = Object.create(null)
    // Get the vnode under group
    const prevChildren = this.prevChildren = this.children
    // Get the DOM under group
    const rawChildren = this.$slots.default || []
    const children = this.children = []
    // Get the transition state of the group
    const transitionData = extractTransitionData(this)
    for(let i = 0; i < rawChildren.length; i ++){
      const c = rawChildren[i]
      if(c.tag){
        if(c.key ! = =null && String(c.key).indexOf('_vlist')! = =0) {// Add the transition state for each element in the current group
          children.push(c)
          map[c.key] = c
          (c.data || (c.data = {})).transition = transitionData
        }else{...// Handle transitionGroup elements without keys}}}if(prevChildren){
      const kept = []
      const removed = []
      // Compare vNodes with the actual DOM, vNodes that need to be retained and deleted
      for(let i = 0; i < prevChildren.length; i ++){
        const c = prevChildren[i]
        c.data.transition = transitionData
        c.data.pos = c.elm.getBoundingClientRect()
        if(map[c.key]){
          kept.push(c)
        }else{
          removed.push(c)
        }
      }
      this.kept = h(tag,null,kept)
      this.removed = removed
    }
    return h(tag,null,children)
  },
  updated(){
    const children = this.prevChildren
    const moveClass = this.moveClass || ((this.name || 'v') + '-move')
    if(! children.length || !this.hasMove(children[0].elm,moveClass)){
      return 
    }
    // Change the position according to the state of the children
    children.forEach(callPendingCbs)
    children.forEach(recordPosition)
    children.forEach(applyTranslation)
    this._reflow = document.body.offsetHeight
    After the event is complete, remove the transition class and remove the event
    children.forEach((c) = > {
      if(c.data.moved){
        const el = c.elm
        const s = el.style
        addTransitionClass(el,moveClass)
        s.transform = s.WebkitTransform = s.transitionDuration = ' '
        el.addEventListener(transitionEndEvent,el._moveCb = function cb(e){
          if( e && e.target ! == el){return 
          }
          if(! e ||/transform$/.test(e.propertyName)){
            el.removeEventListener(transitionEndEvent,cb)
            el._moveCb = null
            removeTransitionClass(el,moveClass)
          }
        })
      }
    })
  }
}
Copy the code