Vue FLIP Test

Vue Transition effect with FLIP style transition of marked element between three pages (using transform and scale only) Calculations done in JS still. Not CSS Optimized

by mgoetzke

HTML

<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/gsap/1.19.1/TweenLite.min.js"></script>
<div id="container">
  <div style="min-height:500px">
    <transition name="fade" v-on:before-leave="beforeLeave" v-on:before-enter="beforeEnter">
      <component :is="page" style="position:absolute"></component>
    </transition>
  </div>
  <button @click="flipPage">FLIP</button>
</div>

CSS

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.4s
}

.fade-enter-active {
  __z-index:-1  
}

.fade-leave-to
/* .fade-leave-active in <2.1.8 */
{
  opacity: 0
}

.fade-enter {
  opacity: 1
}

.primary {
  will-change: translateX translateY scaleX scaleY;
  transform: translateZ(0);
  pointer-events:none;
}

JavaScript

const v = new Vue({
  el: '#container',
  data: {
    page: 'page1'
  },
  methods: {
    flipPage() {
        switch (this.page) {
          case 'page1':
            this.page = 'page2';
            break;
          case 'page2':
            this.page = 'page1';
            break;
            // set previous line to set page to page3 for three steps
          case 'page3':
            this.page = 'page1';
            break;
        }
        //this.page = this.page === 'page1' ? 'page2' : 'page1'
      },
      beforeEnter(el) {
        var primary = el.querySelector('.primary')
        this.newPrimary = primary
      },
      beforeLeave(el) {
        var primary = el.querySelector('.primary')

        if (!primary || !this.newPrimary)
          return

        const newPrimary = this.newPrimary

        //console.log('old', primary)
        //console.log('new', this.newPrimary)

        const oldRect = primary.getBoundingClientRect()
        const newRect = newPrimary.getBoundingClientRect()

        //newPrimary.style.opacity = 1
        //primary.style.opacity = 0
        newPrimary.style.transform = `
        scaleX(${oldRect.width / newRect.width})
        scaleY(${oldRect.height / newRect.height})
        `
        const newRectScaled = newPrimary.getBoundingClientRect()

        const startValues = {
          translateX: oldRect.left - newRectScaled.left,
          translateY: oldRect.top - newRectScaled.top,
          scaleX: oldRect.width / newRect.width,
          scaleY: oldRect.height / newRect.height,
        }

        newPrimary.style.transform = `
      	translateX(${startValues.translateX}px)
        translateY(${startValues.translateY}px)
        scaleX(${startValues.scaleX})
        scaleY(${startValues.scaleY})
        `

        //newPrimary.style['z-index'] = 1000
        primary.style.opacity = 0
        //newPrimary.style.zIndex  = 100000
				//newPrimary.style.position = 'absolute'
        
        const duration = 150;//...