transition tests

by nkovacs

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.16/vue.min.js"></script>
<a href="#" v-on="click: setone">Set one</a>
<a href="#" v-on="click: testsimple">Simple</a>
<a href="#" v-on="click: testback">Back</a>
<a href="#" v-on="click: testquick">Quick</a>
<a href="#" v-on="click: testslow">Slow</a>
<a href="#" v-on="click: testinstant">Instant</a>

<a href="#" v-on="click: set('one')">One</a>
<a href="#" v-on="click: set('two')">Two</a>
<a href="#" v-on="click: set('three')">Three</a>

<section id="main">
    <component is="{{currentView}}" v-transition="page" transition-mode="in-out"></component>
</section>

CSS

#comp1 {
    background: red;
    width: 300px;
    height: 200px;
}
#comp1b {
    background: lightsteelblue;
    height: 50px;
    width: 100px;
}
#comp2 {
    background: blue;
    width: 100px;
    height: 100px;
}
#comp2b {
    background: orange;
    height: 40px;
    width: 200px;
}
#comp3 {
    background: green;
    width: 400px;
    height: 200px;
}

.morphing-box {
    transition: background ease 1.5s, width ease 1.5s, height ease 1.5s, top ease 1.5s, left ease 1.5s, opacity ease 1.5s;
}

/* without this, it acts as css:false, which is buggy */
.page-transition {
    transition: background ease 1.5s;
}

.hiding {
    transition: opacity ease 0.5s;
    opacity: 0;
}

.showing {
    transition: opacity ease 0.5s;
}

.pre-show {
    opacity: 0;
}

JavaScript

Vue.config.debug = true;

var target = null;
var transitioner = null;

function getPosition(elem)
{
    var box = elem.getBoundingClientRect();
    var docElement = document.documentElement;
    return {
    	top: box.top + window.pageYOffset - docElement.clientTop,
    	left: box.left + window.pageXOffset - docElement.clientLeft
    };
}

function morph(source, target, callback) {
    
    var sourceElements = source.querySelectorAll('[data-transition-id]');
    var targetElements = target.querySelectorAll('[data-transition-id]');
    
    var transitionPairs = {};
    
    var i, l;
    var transId;
    
    for (i = 0, l = sourceElements.length; i < l; i++) {
        transId = sourceElements[i].getAttribute('data-transition-id');
        transitionPairs[transId] = {
            source: sourceElements[i]
        };
    }
    
    for (i = 0, l = targetElements.length; i < l; i++) {
        transId = targetElements[i].getAttribute('data-transition-id');
        if (transitionPairs[transId]) {
            transitionPairs[transId].target = targetElements[i];
        }
    }
    
    source.style.position = "absolute";
    var sourcePosition = getPosition(source);
    source.style.top = sourcePosition.top + "px";
    source.style.left = sourcePosition.left + "px";
    target.style.visibility = 'hidden';
    target.style.display = '';
    
    var targetEl;
    var sourceEl;
    var sourceElPosition;
    var sourceStyle;
    var targetStyle;
    var callbackCalled = false; // TODO make it smarter with multiple elements
    // fade out all other elements
    var otherElements = source.querySelectorAll(':not([data-transition-id])');
    for (i = 0, l = otherElements.length; i < l; i++) {
        Vue.util.addClass(otherElements[i], 'hiding');
    }
    
    function handleCallback(sourceEl) {
        if (!callbackCalled && callback !== undefined) {
            callbackCalled = true;
            var trdone = function() {
               ...