el evento de fin de transición se dispara dos veces


Tengo el siguiente código y mi problema es que el evento transitionend se dispara dos veces. No se que esta causando esto. Sospeché que los prefijos de los vendedores lo causaron, pero no lo hacen. Incluso si solo dejo transitionend y transition se disparará dos veces.

CSS

transition: 1s ease-out;

JS

document.addEventListener('click', function (e) {
    var submarine = document.querySelector('.submarine');
    var submarineX = e.clientX - submarine.offsetWidth / 2;
    var submarineY = e.clientY - submarine.offsetHeight / 2;

    submarine.style.left = submarineX + "px";
    submarine.style.top = submarineY + "px";
});

document.addEventListener('transitionend', function (event) {
    console.log(event.type + " " + new Date().getTime());
});

Fiddle

document.addEventListener('transitionend', function (event) {
    console.log(event.type + " " + new Date().getTime());
});

document.addEventListener('click', function (e) {
    var submarine = document.querySelector('.submarine');
    var submarineX = e.clientX - submarine.offsetWidth / 2;
    var submarineY = e.clientY - submarine.offsetHeight / 2;

    submarine.style.left = submarineX + "px";
    submarine.style.top = submarineY + "px";
});
.submarine {
    position: absolute;
    top: 0;
    left: 0;
    width: 20px;
    height: 20px;
    background-color: red;
    border-radius: 50%;
    transition: 1s ease-out;
}
<div class="submarine"></div>
Author: Jonathan, 2013-09-09

5 answers

transitionend se activa para cada propiedad en transición, en su caso top y left.

Puede acceder a la propiedad asociada con el evento en event.propertyName.

No hay evento "transitionsend", por lo que probablemente necesitará algo de hackiness, como filtrar el manejo de devolución de llamada transitionend para solo una de las propiedades de transición. Por ejemplo:

function (event) {
    if (event.propertyName == 'top') {
        //put your code here
    }
});

Ps. Ningún navegador activa el evento MSTransitionEnd. Fue en algún momento en el MS docs, pero en algún momento antes de la versión beta de IE10 que fue reemplazado por el evento estándar transitionend.

 67
Author: Fabrício Matté,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-19 17:49:23

El evento se desencadena por cada propiedad que ha sido la transición.

La forma propertyName que Fabricio sugirió es la forma correcta de hacer esto, sin embargo, dependiendo de las circunstancias, también puede usar one();, así.

$(document).one('transitionend webkitTransitionEnd MSTransitionEnd', function() {
   ...
});
 7
Author: iConnor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-08 22:12:45

Para cualquiera que busque una solución simple de copiar y pegar una sola vez (solo he incluido el CSS necesario). Esto no responde a la pregunta y sí responde a lo que estaba buscando cuando aterricé aquí.

CSS:

.my-elem {
    transition: height 0.5s ease-out, opacity 0.5s ease-out;
}

JavaScript:

var elem = document.querySelector(".my-elem");

var transitionCounter = 0;

var transitionProp = window.getComputedStyle(elem , null)["transition-property"] || "";

// We just need to know how many transitions there are
var numTransitionProps = transitionProp.split(",").length;

elem.addEventListener("transitionend", (event) => {
  // You could read event.propertyName to find out which transition was ended, 
  // but it's not necessary if you just want to know when they are all done.
  if (transitionCounter < (numTransitionProps - 1)) {
    transitionCounter++;
  } else {
    transitionCounter = 0; // reset
    alert("I'm done!!!"); // do what you need to
  }
}, false);

Probado en IE11, Chrome 48 y Firefox 37.

 4
Author: TJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-10 14:54:53

Para cualquiera que todavía esté buscando una solución más robusta, como el evento "allTransitionEnd", he implementado un jQuery "special event", más como una prueba de concepto para algo en lo que estaba trabajando, pero podría poner una lib en Github.

Echa un vistazo a la JSBin.

Es bastante complicado, así que no explicaré demasiado, pero hace que sea muy fácil hacer cosas después de que TODAS las transiciones hayan terminado en un elemento:

$(function () {

    $element.on('allTransitionEnd', function () {
        // do something after all transitions end.
    });

});

Funciona sondeando el elemento para la transición propiedades, luego se vincula a los eventos nativos transitionend (incluidos los específicos del proveedor) para realizar un seguimiento de las propiedades que han finalizado la transición. Cuando todos han terminado la transición, activa cualquier manejador allTransitionsEnd enlazado y luego borra las propiedades de transición, en caso de que también hayan cambiado, y sondea para ellos la próxima vez.

Esto es realmente útil cuando se están haciendo transiciones de varias propiedades con retardo y/o duración variables y, después de todo, desea hacer algo las transiciones se han completado.

Ejemplos de casos de uso:

  • Elimine un mensaje flash después del fundido de salida y reduzca.
  • Activación de eventos "abiertos" y "cerrados" en un componente reutilizable, como un menú o modal, donde los consumidores pueden querer ejecutar alguna lógica después de que la transición haya terminado, sin entrometerse en transiciones css.

Si solo está haciendo la transición de una propiedad, o no tiene retrasos y/o duraciones variadas, entonces funciona una solución simple fino.

Funciona en la última versión de Chrome, Firefox, Safari, Mobile Safari y IE11 e IE10. No funciona en IE8 porque las transiciones no son compatibles. Enlazar a un evento nativo adicional como reserva.

 3
Author: Stoutie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-14 08:53:15

Esta es una pregunta relativamente antigua, pero pensé en compartir mi respuesta:

function OnTransitionEvent() {
    var t,
        el = document.createElement('transitionElement');

    var transitions = {
        'transition'      : 'transitionend',
        'OTransition'     : 'oTransitionEnd',
        'MozTransition'   : 'transitionend',
        'WebkitTransition': 'webkitTransitionEnd'
    };

    for (t in transitions){
        if (el.style[t] !== undefined){
            return transitions[t];
        }
    }
}

var transitionEvent = OnTransitionEvent();

$(document).one(transitionEvent, function() { 
    console.log('done');
});
 -2
Author: rotaercz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-08 00:49:55