1
votes

Est-il possible de vérifier si une transition CSS est terminée SANS utiliser d'événements?

Est-il possible, d'une manière ou d'une autre, via JavaScript, de vérifier qu'une transition CSS est terminée sans s'inscrire préalablement aux événements de transition?

Le problème est:

  • J'ai une application Web qui utilise des transitions CSS pour la décoloration de certains éléments lors du chargement de la page
  • Je ne peux pas modifier ce code JavaScript d'applications Web
  • Lorsque j'accède à cette page, je peux exécuter JavaScript dans la console du navigateur
  • Je veux m'assurer que la transition CSS est terminée à 100% avant de continuer avec mon code de script java personnalisé
  • dans la console du navigateur, je pourrais accrocher à l'événement de transition, mais cela échouerait dans de nombreux cas car:
    • l'élément de transition n'est pas encore là
    • L'animation est déjà terminée lorsque j'ai configuré le hook

Est-il possible de vérifier via JavaScript si la transition CSS pour l'élément est terminée? À tout moment?

Je ne peux pas utiliser les événements JavaScript (comme par exemple: https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/ )


5 commentaires

Événement signifie que quelqu'un vous avertit. Ne pas utiliser d'événements signifie que personne ne vous avertit. Cela signifie que vous devez interroger. L'interrogation GUI a été utilisée pour la dernière fois en mode DOS 16 bits.


C'est possible, je cherche mon projet plus ancien à la recherche d'un exemple, si je trouve que je vais poster. @ceving, il n'y a rien de mal avec l'interrogation GUI, tant qu'elle est bien faite.


"L'interrogation GUI a été utilisée pour la dernière fois en mode DOS 16 bits". il est utilisé dans le cadre de l'automatisation


Le sondage GUI @ibrahimtanyalcin ne peut pas être bien fait, car c'est une idée stupide.


@ceving, des idées "stupides" peuvent être nécessaires dans des circonstances où les meilleures ne peuvent pas être utilisées. Ce n'est pas une question de solution optimale, c'est par nécessité comme le PO l'a décrit. Et deuxièmement, je vous conseillerais d'utiliser une meilleure langue lorsque vous parlez aux autres, sinon montrez au moins un peu de "skin in the game" en mettant une vraie photo de profil.


3 Réponses :


3
votes

Non

Le mieux que vous puissiez faire est de regarder le CSS pour voir la durée de la transition.


1 commentaires

OK merci. J'avais peur que ce soit vraiment le cas, mais je ne savais pas avec certitude: - /



0
votes

Pas une réponse mais un POC rapide sur lequel s'appuyer:

<div id="element">
  <p>Click somewhere</p>

  currently transitioning:
  <ul id="out"></ul>
  
</div>
html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

#element {
  cursor: pointer;
  width: 100%;
  height: 100%;
  padding: 20px;
  transition: all 1s;
}
element.onclick = function() {
  const color = 0x1000 | (Math.random() * 0x1000);
  
  const prop = Math.random() < .5? "background-color": "color";
  
  element.style[prop] = "#" + color.toString(16).slice(-3);
}

let curr = {};
requestAnimationFrame(function check() {
  const prev = curr;

  curr = Object.assign({}, getComputedStyle(element));

  const changed = Object.keys(curr).filter(key => curr[key] !== prev[key]);

  out.innerHTML = changed.map(key => `<li>${key}</li>`).join("\n");

  requestAnimationFrame(check);
});

vous remarquerez le scintillement, car deux images adjacentes peuvent ne pas différer pendant cette interpolation. Vous voudriez mettre en cache plus d'images et comparer quelque chose comme 5 à 10 images à part; dépend de la méthode d'interpolation que vous utilisez et de la durée d'une transition.

De plus, en fonction des propriétés que vous vérifiez, vous pouvez également comparer getComputedStyle (element) [key] contre element.style [clé] au lieu de stocker les valeurs pour plusieurs cadres. Mais cela ne fonctionne pas pour la couleur (et d'autres), car il y a tellement de façons de décrire la même couleur.


1 commentaires

merci pour cette solution de contournement! peut-être que je peux en quelque sorte appliquer ce genre de hack



0
votes

C'EST POSSIBLE

CHAINES TIMED ;

Désolé pour le retard, était en réunion. J'ai recherché l'un de mes anciens projets, mais je n'ai pas pu le trouver. Je vais esquisser l'idée ici, j'ai d'abord pensé que nous pourrions peut-être opter pour Mutation Observer, mais nous devons également y faire des contrôles périodiques. Donc je suppose que celui-ci fera l'affaire. Vous devez d'abord éviter certaines choses:

  • appeler getComputedStyle à chaque image, c'est une mauvaise idée, car c'est une fonction très coûteuse à appeler et déclenche la mise en page, vous devriez donc ralentir à la place.
  • objet de style copie papier, c'est-à-dire un objet volumineux à copier, vous devriez donc passer un argument pour une propriété spécifique
  • en travaillant avec une référence de nœud, si le nœud n'est pas là comme vous l'avez dit, cela générera une erreur de référence, utilisez plutôt une fonction pour renvoyer le nœud.

La première chose à faire est d'écrire une fonction d'assistance, une fonction qui exécuterait périodiquement une fonction de test et qui retournerait si elle réussit:

var selection  = new Select(document.getElementById("someDiv"));
selection
.style("width","100px",function(propName){alert(propName + " changed!");})
.style("height","100px",function(propName){alert(propName + " changed!");})
.style("transform","scale(0.5,0.5)",function(propName){alert(propName + " changed!");});

Le suivant est la fonction réelle, je dirais pas besoin de créer un nouvel objet, nous pouvons créer une fonction avec 3 arguments (2 optionnels), le nœud "fonctor", la propriété de style à vérifier et enfin la fonction à appeler.

function Select(node){
  this.node = node;
};
  Select.prototype.style = function(prop,value,f){
    var node = this.node;
    this.node.style[prop] = value;
    f && onTransitionEnd(
      function(){return node;},
      prop,
      f
    );
    return this;
  };

La précision par défaut de 5 signifie que la fonction vérifiera toutes les 5 ticks, 5 * 17 millisecondes les valeurs pour déterminer si la transition s'est terminée. Le délai d'expiration est également facultatif, il annulera l'exécution après une certaine période.

Ce n'est pas un problème si le nœud n'est PAS là, car nous passons une fonction qui renvoie le nœud ou null, si le nœud est pas là, il ne s'exécutera pas.

Ci-dessus est une promesse et renverrait un objet "alorsable" que vous pouvez enchaîner comme vous le souhaitez.

Cas d'utilisation simple, par exemple juste après avoir changé un style ou une classe:

document.getElementById("someDiv").className = "def c1";
onTransitionEnd(
  function(){return document.getElementById("someDiv");},
  "transform",
  function(prop){alert("heyy!!"); return this;}
).then(function(node){
    node.className  = "def";
    return onTransitionEnd(
    function(){return document.getElementById("someDiv");},
    "transform",
    function(){alert("heyy-2!!"); return this;}
  );
}).then(function(node){
    alert("id is " + node.id);
});

il vous alerterait maintenant "heyy". Pour enchaîner ceci:

document.getElementById("someDiv").className = "def c1";
onTransitionEnd(
  function(){return document.getElementById("someDiv");},
  "transform",
  function(){alert("heyy!!");}
);

Voici quelques exemples:

pour que le dernier fonctionne, ouvrez la console développeur, sélectionnez le div bleu et changez son id en "someDiv", la fonction s'exécutera.

Vous pourriez vous demander si vous devez appeler onTransitionEnd chaque fois que vous modifiez le style, dans ce cas, vous pouvez écrire un wrapper. Si vous n'avez pas d'idée, faites-moi savoir que je l'écrirai aussi.

De toute évidence, vous n'avez pas utilisé de wrapper, voici donc un wrapper d'aide:

 function onTransitionEnd(fNode,prop,f,precision,timeout){
    precision = precision || 5;
    timeout = timeout || Infinity;
    return new Promise(function(res){
      var node = fNode(),
          oValue = node && getComputedStyle(node)[prop],
          currentFrame = watchman(
            fNode,
            function(counter){ 
              if(counter.counter * 17 >= timeout){
                window.cancelAnimationFrame(currentFrame.value);
              }
              if(++counter.counter % precision === 0) {
                if(!this()){return}
                var nValue = getComputedStyle(this())[prop];
                if(nValue === oValue) {
                  return true;
                }
                oValue = nValue;
              }
            },
            function(counter){
              res(f.call(fNode(),prop));
            },
            {counter:0}
          );
    });
  };

3 commentaires

salut ibrahim! merci pour votre temps! Votre solution m'a aidé à comprendre toute la problématique. Il semble qu'il n'y ait pas d'autre possibilité que de vérifier à plusieurs reprises si la propriété a changé, etc. Par exemple, si je modifie légèrement votre premier exemple, cela échoue. Le "onTransitionEnd" alerte déjà, même si l'animation n'a pas encore été lancée. onTransitionEnd (function () {return document.getElementById ("someDiv");}, "transform", function () {alert ("heyy !!");}); setTimeout (function () {document.getElementById ("someDiv"). className = "def c1";}, 10000);


merci pour la réponse. Cela m'a beaucoup aidé! Pas besoin de répondre plus loin :-)


C'est parce qu'il vous manque encore 1 élément de plus, et c'est le concept du «wrapper», je vous ai demandé si vous le saviez ou non. Votre exemple ne fonctionne pas simplement parce que vous n'utilisez pas de wrapper. Vérifiez la réponse mise à jour, vous ne devez pas vous hâter lorsque vous décidez. Prenez votre temps et réfléchissez bien.