Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Feature detection for transtionend/animationend event?

I'm looking for a cleaner way to feature detect the actual name of the transitionend. I've seen a lot of examples just brute force adding handlers to all the variations. Also, I don't want to have to rely on jQuery (or similar framework).

I'm basically starting with this list and hoping to just bind the best fit (i.e., first in list to match).

var transitionendName,
    events = [
        'transitionend',
        'webkitTransitionEnd',
        'MozTransitionEnd',
        'oTransitionEnd'
    ];

// ^^^^^ your code here

myElem.addEventListener(transitionendName, myHandler, false);

Anyone feel they have a clean solution to this? The same solution presumably will work for animationend events.

Edit: msTransitionEnd and '-ms-' prefixed properties were removed in one of the final IE10 release candidates.

like image 548
mckamey Avatar asked Oct 10 '12 00:10

mckamey


2 Answers

You can register all the event end names and then trigger a very short CSS transition and see which one fires. Also, IE10, uses transitionend, so there is no browser that uses msTransitionEnd.

Here's an example of how to do that: http://jsfiddle.net/jfriend00/5Zv9m/

var transitionendName,
    events = [
        'transitionend',
        'webkitTransitionEnd',
        'MozTransitionEnd',
        'oTransitionEnd'
    ];

function findTransitionEnd(callback) {
    // add an off-screen element
    var elem = document.createElement("div");
    elem.id = "featureTester";
    document.body.appendChild(elem);

    // clean up temporary element when done
    function cleanup() {
        document.body.removeChild(elem);
        elem = null;
    }

    // set fallback timer in case transition doesn't trigger
    var timer = setTimeout(function() {
        if (!transitionendName) {
            cleanup();
            callback("");
        }
    }, 200);

    // register all transition end names
    for (var i = 0; i < events.length; i++) {
        (function(tname) {
            elem.addEventListener(tname, function() {
                if (!transitionendName) {
                    transitionendName = tname;
                    clearTimeout(timer);
                    cleanup();
                    callback(tname);
                }

            });
        })(events[i]);
    }


    // trigger transition
    setTimeout(function() {
        elem.className = "featureTestTransition";
    }, 1);
}
like image 138
jfriend00 Avatar answered Sep 30 '22 12:09

jfriend00


Another variation which qualifies for pure feature detection (rather than a purely pragmatic solution) but is more efficient:

var transitionendNames = [
    'transitionend',
    'webkitTransitionEnd',
    'MozTransitionEnd',
    'oTransitionEnd'
];

/**
 * Helper function to bind to the correct transitionend event
 * @param {function} callback The function to call when the event fires
 */
var transitionend = function(elem, callback) {
    var handler = function(e) {
        //console.log('transitionend == '+e.type);

        // test in case multiple were registered before change
        if (transitionendNames) {
            // store the actual name
            var transitionendName = e.type;

            // every other time, bind only to actual event
            transitionend = function(elem, callback) {
                elem.addEventListener(transitionendName, callback, false);
            };

            // flag for any others
            transitionendNames = null;
        }
        return callback.call(elem, e);
    };

    // until an event has been triggered bind them all
    for (var i=0, len=transitionendNames.length; i<len; i++) {
        elem.addEventListener(transitionendNames[i], handler, false);
    }
};
like image 43
mckamey Avatar answered Sep 30 '22 10:09

mckamey