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;//...