Transition event with multiple transitions, detection of the last transition

transitionEndthe event is fired when a transition ends with the first , not the 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>
Run code

Now, when I check Chrome (I do not use this browser), I see that the event is fired 3 times, one per transition. In any case, I need it to work for the latter, and in Firefox. (I don’t know how many transitions there were on the element anyway to find out what was the last)

+5
source share
3 answers

transitionEndreturns a property called propertyNamein the event object. Source

, , , :

document.querySelector('a').addEventListener('transitionend', function(event){
    if(event.propertyName !== 'width') return;
    console.log('transitionEnd - width!');
});
+3

, css . , window.getComputedStyle <a> duration delay.

, ( ) , , .

:

  • Css ms s , .
  • , , 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>
+2

, . :

document.querySelector('a').addEventListener('click', function(e){
  this.classList.toggle('animate');
  let style = window.getComputedStyle(this, null);
  Promise.all(style.transition.split(',').map((prop) => {
     prop = prop.trim().split(/\s+/);
     return Promise.race([
         new Promise((resolve) => {
              let h = (e) => {
                   if (e.propertyName == prop[0])
                        resolve('transitionEnd ' + prop[0]);
              };
              this.addEventListener('transitionend', h, {once:false});
         }),
         new Promise((resolve) => 
              setTimeout(
                  () => resolve('TIMEOUT ' + prop[0]),
                  prop[1].replace(/s/,'')*1000 + 100
              )
         )
     ])
  }))
  .then((res) => {
     console.log(res + 'DONE!!!!');
     /*  do your stuff */
  });
});

:

  • , , // . , : " 4s 0 , 2 0 ,.."
  • Promise.race, transitionEnd ( prop , prop (background background-color), ) tp
  • , - /eventListeners

:

  • this is an example, I admit that he uses a lot of magic, and missed a lot of checks
  • The callback will be triggered even if the animation has been canceled (the timeout is triggered anyway)
  • requires ES6 :)

you can play with him on jsfiddle

0
source

Source: https://habr.com/ru/post/1660410/


All Articles