Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

transitionEnd event with multiple transitions, detect last transition

Tags:

javascript

dom

transitionEnd event is fired on the transition which ends first and not last, which is not the desired behavior. Any workarounds?

document.querySelector('a').addEventListener('transitionend', function(){
  var time = (new Date().getMinutes()) + ':' + (new Date().getSeconds());
  console.log('transitionEnd - ', time);
});
a{
  display:block;
  opacity:.5;
  width:100px;
  height:50px;
  background:lightblue;
}
a:hover{
  width:200px;
  height:100px;
  background:red;
  transition: 4s width,     /* <-- "transitionEnd" should fire after this */
              2s height,
              .5s background;  
}
<a>Hover me</a>

Now that I check on Chrome (I do not use that browser), I see that the event gets called 3 times, one per transition. Anyway, I need it to fire for the last one, and in Firefox. (I can't know how many transitions were on the element anyway, to know which was the last)

like image 234
vsync Avatar asked Nov 10 '16 15:11

vsync


2 Answers

transitionEnd returns a property called propertyName in the event object. Source

Therefore you can test for the property you want and use simple logic to filter the callbacks:

document.querySelector('a').addEventListener('transitionend', function(event){
    if(event.propertyName !== 'width') return;
    console.log('transitionEnd - width!');
});
like image 193
sidonaldson Avatar answered Oct 01 '22 10:10

sidonaldson


A bit of a hacky solution might be to try to find out which css property has the longest total duration. You can do so by using window.getComputedStyle on your <a> element and adding up all duration and delay properties.

You could do this in the regular event handler that is fired three times (it's pretty quick), or make a function that pre-computes the property name you're looking for.

Main problems with this approach:

  • Css allows you to use ms and s in one statement, you might need to do some more computing.
  • It can be kind of difficult to predict what the computed style is when you're changing the transition style on hover, or when adding new classes just before/after a transition.

var getValues = function(str) {
  return str
    .replace(/[A-Z]/gi, "")
    .split(", ")
    .map(parseFloat);
};

var getMaxTransitionProp = function(el) {
  var style = window.getComputedStyle(el);
  var props = style.transitionProperty.split(", ");

  var delays = getValues(style.transitionDelay);
  var durations = getValues(style.transitionDuration);
  var totals = durations.map(function(v, i) {
    return v + delays[i];
  });

  var maxIndex = totals.reduce(function(res, cur, i) {
    if (res.val > cur) {
      res.val = cur;
      res.i = i;
    }
    return res;
  }, {
    val: -Infinity,
    i: 0
  }).i;

  return props[maxIndex];
}

var lastEventListenerFor = function(el, cb) {
  var lastProp = getMaxTransitionProp(el);
  return function(e) {
    if (e.propertyName == lastProp) {
      cb(e);
    }
  };
}

var a = document.querySelector("a");
var cb = function(e) {
  console.log("End");
};

a.addEventListener("transitionend", lastEventListenerFor(a, cb));
a {
  display: block;
  opacity: .5;
  width: 100px;
  height: 50px;
  background: lightblue;
  transition: 3s width,
  /* <-- "transitionEnd" should fire after this */
  2s height, .5s background;
}
a:hover {
  width: 200px;
  height: 100px;
  background: red;
}
<a>Hover me</a>
like image 29
user3297291 Avatar answered Oct 01 '22 09:10

user3297291