Wie kann ich eine WebKit-CSS-Animation über JavaScript erneut auslösen?

77

Also habe ich diese -webkit-animationRegel:

@-webkit-keyframes shake {
    0% {
        left: 0;
    }
    25% {
        left: 12px;
    }
    50% {
        left: 0;
    }
    75% {
        left: -12px;
    }
    100% {
        left:0;
    }
}

Und einige CSS, die einige der Animationsregeln auf meinem definieren box:

#box{
    -webkit-animation-duration: .02s;
    -webkit-animation-iteration-count: 10;
    -webkit-animation-timing-function: linear;
}

Ich kann shakedas #boxmögen:

document.getElementById("box").style.webkitAnimationName = "shake";

Aber ich kann es später nicht noch einmal schütteln.

Dies schüttelt die Box nur einmal:

someElem.onclick = function(){
    document.getElementById("box").style.webkitAnimationName = "shake";
}

Wie kann ich eine CSS-Animation über JavaScript erneut auslösen, ohne Zeitüberschreitungen oder mehrere Animationen zu verwenden?

David Murdoch
quelle
Ist jQuery oder eine ähnliche Bibliothek eine Option? Sie würden wahrscheinlich eine bessere Browserunterstützung sehen.
Surreale Träume
jQuery ist verfügbar, aber in meinem Fall nicht wirklich anwendbar. Ich benötige keine andere Browserunterstützung, da diese nur in Adobe Air ausgeführt wird. Ich versuche, mich an CSS-Animationen anstatt an Javascript zu halten.
David Murdoch
CSS-Tricks Artikel
Blazemonger

Antworten:

94

Ich fand die Antwort basierend auf dem Quellcode und den Beispielen auf der Github-Seite für CSS3-Übergangstests .

Grundsätzlich haben CSS-Animationen ein animationEndEreignis, das ausgelöst wird, wenn die Animation abgeschlossen ist.

Für Webkit-Browser heißt dieses Ereignis " webkitAnimationEnd". Um eine Animation nach dem Aufruf zurückzusetzen, müssen Sie dem Element für das animationEndEreignis einen Ereignis-Listener hinzufügen .

In einfachem Vanille-Javascript:

var element = document.getElementById('box');

element.addEventListener('webkitAnimationEnd', function(){
    this.style.webkitAnimationName = '';
}, false);

document.getElementById('button').onclick = function(){
    element.style.webkitAnimationName = 'shake';
    // you'll probably want to preventDefault here.
};

und mit jQuery:

var $element = $('#box').bind('webkitAnimationEnd', function(){
    this.style.webkitAnimationName = '';
});

$('#button').click(function(){
    $element.css('webkitAnimationName', 'shake');
    // you'll probably want to preventDefault here.
});

Der Quellcode für CSS3-Übergangstests (oben erwähnt) enthält das folgende supportObjekt, das für browserübergreifende CSS-Übergänge, -Transformationen und -Animationen hilfreich sein kann.

Hier ist der Support-Code (neu formatiert):

var css3AnimationSupport = (function(){
    var div = document.createElement('div'),
        divStyle = div.style,
        // you'll probably be better off using a `switch` instead of theses ternary ops
        support = {
            transition:
                divStyle.MozTransition     === ''? {name: 'MozTransition'   , end: 'transitionend'} :
                // Will ms add a prefix to the transitionend event?
                (divStyle.MsTransition     === ''? {name: 'MsTransition'    , end: 'msTransitionend'} :
                (divStyle.WebkitTransition === ''? {name: 'WebkitTransition', end: 'webkitTransitionEnd'} :
                (divStyle.OTransition      === ''? {name: 'OTransition'     , end: 'oTransitionEnd'} :
                (divStyle.transition       === ''? {name: 'transition'      , end: 'transitionend'} :
                false)))),
            transform:
                divStyle.MozTransform     === '' ? 'MozTransform'    :
                (divStyle.MsTransform     === '' ? 'MsTransform'     :
                (divStyle.WebkitTransform === '' ? 'WebkitTransform' : 
                (divStyle.OTransform      === '' ? 'OTransform'      :
                (divStyle.transform       === '' ? 'transform'       :
                false))))
            //, animation: ...
        };
    support.transformProp = support.transform.name.replace(/([A-Z])/g, '-$1').toLowerCase();
    return support;
}());

Ich habe den Code nicht hinzugefügt, um "Animationseigenschaften" für jeden Browser zu erkennen. Ich habe diese Antwort "Community Wiki" gemacht und überlasse das dir. :-)

David Murdoch
quelle
Der zitierte Quellcode wurde nach github.com/louisremi/jquery.transition.js
Tom Sarduy
2
Hinweis: Der Code im Github-Repo hat sich seit dieser Antwort geändert. Der Code dort und der Code hier sind jetzt völlig anders.
David Murdoch
1
Beachten Sie, dass wenn es eine CSS-Regel gibt, die die Animation dem Objekt zuweist '', wenn Sie sie auf festlegen, sie von der CSS-Regel erben würde, müssen Sie sie in diesem Fall festlegen none.
user202729
13

Sie müssen zuerst die Animation entfernen und dann erneut hinzufügen. Z.B:

document.getElementById("box").style.webkitAnimationName = "";
setTimeout(function ()
{
    document.getElementById("box").style.webkitAnimationName = "shake";
}, 0);

Um dies ohne setTimeout zu tun, entfernen Sie die Animation während onmousedownund fügen Sie sie hinzu während onclick:

someElem.onmousedown = function()
{
    document.getElementById("box").style.webkitAnimationName = "";
}
someElem.onclick = function()
{
    document.getElementById("box").style.webkitAnimationName = "shake";
}
gilly3
quelle
Yah, das ist das gleiche wie das, was ich mir ausgedacht habe. Aber ich möchte wenn möglich auf das setTimeout verzichten.
David Murdoch
1
Ich habe meine Antwort mit einer Alternative aktualisiert, die setTimeout nicht verwendet.
Gilly3
7

Nach dem Vorschlag von https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Tips , entfernen und dann die Animation - Klasse hinzufügen, indem request um sicherzustellen , dass die Rendering - Engine sowohl Änderungen verarbeitet. Ich denke, dies ist sauberer als die Verwendung von setTimeout und behandelt die Wiedergabe einer Animation, bevor das vorherige Spiel abgeschlossen ist.

$('#shake-the-box').click(function(){   
  $('#box').removeClass("trigger");
  window.requestAnimationFrame(function(time) {
  window.requestAnimationFrame(function(time) {
      $('#box').addClass("trigger");
    });
    });    

});

http://jsfiddle.net/gcmwyr14/5/

Debby Mendez
quelle
6

Eine einfache aber effektive Alternative:

HTML:

<div id="box"></div>
<button id="shake-the-box">Shake it!</button>

CSS:

#box{
    background: blue;
    margin:30px;
    height:50px;
    width:50px;
    position:relative;
    -moz-animation:shake .2s 0 linear 1; 
    -webkit-animation:shake .2s 0 linear 1; 
}
#box.trigger{
    display:table;
}
@-webkit-keyframes shake {
    0% {
        left: 0;
    }
    25% {
        left: 12px;
    }
    50% {
        left: 0;
    }
    75% {
        left: -12px;
    }
    100% {
        left:0;
    }
}
@-moz-keyframes shake {
    0% {
        left: 0;
    }
    25% {
        left: 12px;
    }
    50% {
        left: 0;
    }
    75% {
        left: -12px;
    }
    100% {
        left:0;
    }
}​

jQuery:

$('#shake-the-box').click(function(){

  $('#box').toggleClass('trigger');

});​

Demo:
http://jsfiddle.net/5832R/2/

Probleme:
Ich weiß nicht, ob es unter Firefox funktioniert, da die Animation dort nicht zu funktionieren scheint ...

Puyol
quelle
Dies funktioniert, aber aus irgendeinem Grund wird die Überlaufregel ignoriert. Ich habe sie auf versteckt gesetzt, aber nachdem der Animationsüberlauf zeigt
Schneemann
1

Klon funktioniert ziemlich gut bei angehaltenem Karaoke: Bei IE11 musste ein Reflow erzwungen werden (R. Krupińskis kürzere Version).

$('#lyrics').text("Why does it hurt when I pee?");
changeLyrics('3s');  

function changeLyrics(sec) {
  str = 'lyrics '+ sec + ' linear 1';
  $('#lyrics').css( 'animation', str);
  $('#lyrics').css( 'animation-play-state', 'running' );
  $('#lyrics').replaceWith($('#lyrics').clone(true)); 
}

oder Sie können Folgendes verwenden:

function resetAnimation(elm) {
  $('#'+elm).replaceWith($('#'+elm).clone(true)); 
}
user3026911
quelle
1

Setzen Sie zuerst den Wert zurück. Verwenden Sie den Reflow, um die Änderung ohne Timeout anzuwenden:

function shake() {
  var box = document.getElementById("box");
  box.style.animationName = null;
  box.offsetHeight; /* trigger reflow */
  box.style.animationName = "shake";
}
@keyframes shake {
    0% { left: 0; }
   25% { left: 12px; }
   50% { left: 0; }
   75% { left: -12px; }
  100% { left: 0; }
}

#box {
    position: absolute;
    width: 75px; height: 75px;
    background-color: black;
    animation-duration: .02s;
    animation-iteration-count: 10;
    animation-timing-function: linear;
}

button {
    position: absolute;
    top: 100px;
}
<div id="box"></div>
<button onclick="shake()">Shake</button>

Im Gegensatz zu der akzeptierten Antwort, die empfohlen wird animationEnd, setzt diese Methode die Animation zurück, auch wenn sie noch ausgeführt wird. Dies könnte sein oder nicht, was Sie wollen.


Eine Alternative wäre, eine doppelte @keyframesAnimation zu erstellen und zwischen den beiden zu wechseln:

function shake() {
  var box = document.getElementById("box");
  if (box.style.animationName === "shake")
      box.style.animationName = "shake2";
  else
      box.style.animationName = "shake";
}
@keyframes shake {
    0% { left: 0; }
   25% { left: 12px; }
   50% { left: 0; }
   75% { left: -12px; }
  100% { left: 0; }
}

@keyframes shake2 {
    0% { left: 0; }
   25% { left: 12px; }
   50% { left: 0; }
   75% { left: -12px; }
  100% { left: 0; }
}

#box {
    position: absolute;
    width: 75px; height: 75px;
    background-color: black;
    animation-duration: .02s;
    animation-iteration-count: 10;
    animation-timing-function: linear;
}

button {
    position: absolute;
    top: 100px;
}
<div id="box"></div>
<button onclick="shake()">Shake</button>

Nutzer
quelle
Anmerkung: pro stackoverflow.com/questions/21664940/... , kann es besser sein , zB zu verwenden void( box.offsetHeight);statt, weil Aussage mit var Zugang und ohne Wirkung optimiert werden kann (und wird Linters auslösen Warnungen auszusenden wie Unexpected expression '.' in statement position.- mit freundlicher Genehmigung von JSLint)
Beachten Sie außerdem, dass Rückflüsse ziemlich "schwere" (rechenintensive) Operationen sind.
1

Gibt es ein Problem mit der Verwendung setTimeout(), um die Klasse zu entfernen und sie 5 ms später zu lesen?

svg.classList.remove('animate');
setTimeout(function() {
  svg.classList.add('animate');
}, 10);
Jeremy Lynch
quelle
0

Mit Ihrem Javascript können Sie auch eine CSS-Klasse hinzufügen (und dann entfernen), in der die Animation deklariert ist. Verstehst du, was ich meine ?

#cart p.anim {
  animation: demo 1s 1; // Fire once the "demo" animation which last 1s
}
Nico Prat
quelle
0

1) Fügen Sie dem #box.triggerCSS einen Animationsnamen hinzu

#box.trigger{
    display:table;
    animation:shake .2s 0 linear 1;
    -moz-animation:shake .2s 0 linear 1; 
    -webkit-animation:shake .2s 0 linear 1;
}

2) In Java-Skript können Sie die Klasse nicht entfernen trigger.

3) Entfernen Sie den Klassennamen mithilfe der setTimeOutMethode.

$(document).ready(function(){
    $('#shake-the-box').click(function(){

    $('#box').addClass('trigger');
    setTimeout(function(){
        $("#box").removeClass("trigger")},500)        
    });
}); 

4) Hier ist die DEMO .

Vamsi Velaga
quelle