2011-01-25 1 views
69

Così, ho questo -webkit-animation regola:Come posso riattivare un'animazione CSS WebKit tramite JavaScript?

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

E alcuni CSS che definisce alcune regole di animazione sul mio box:

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

posso shake il #box in questo modo:

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

Ma non riesco a scuoterlo più tardi.

Questo scuote solo la casella di una volta:

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

Come posso ri-trigger un'animazione CSS tramite JavaScript senza l'utilizzo di timeout o animazioni multiple?

+0

jQuery o una libreria simile è un'opzione? Probabilmente vedrai un supporto migliore per il browser. –

+0

jQuery è disponibile ma non è realmente applicabile nel mio caso. Non ho bisogno di altro supporto per il browser poiché verrà eseguito solo in Adobe Air. Sto cercando di rimanere con le animazioni css invece di javascript. –

+1

Rilevante: [Firmin - Libreria di animazioni JavaScript che utilizza trasformazioni e transizioni CSS] (http://extralogical.net/projects/firmin/) –

risposta

90

ho trovato la risposta in base al codice sorgente e gli esempi al CSS3 transition tests github page.

Fondamentalmente, le animazioni CSS hanno un evento animationEnd che viene generato al termine dell'animazione.

Per i browser Webkit questo evento è denominato "webkitAnimationEnd". Pertanto, per ripristinare un'animazione dopo che è stata chiamata, è necessario aggiungere un listener di eventi all'elemento per l'evento animationEnd.

in JavaScript vaniglia:

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. 
}; 

e con jQuery:

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

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

Il codice sorgente per CSS3 transition tests (di cui sopra) ha la support seguente oggetto che può essere utile per il cross -Browser Transizioni CSS, trasformazioni e animazioni.

Ecco il codice di supporto (ri-formattato):

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; 
}()); 

non ho aggiunto il codice per rilevare le proprietà “animazione” per ciascun browser. Ho fatto questa risposta "wiki della comunità" e lasciatelo a voi. :-)

+0

il codice sorgente citato è stato spostato in https://github.com/louisremi/jquery.transition.js/ –

+0

grazie, collegamento fisso. –

+2

Nota: il codice nel repository github è cambiato da questa risposta; il codice lì e il codice qui sono completamente diversi ora. –

11

È necessario prima rimuovere l'animazione, quindi aggiungerlo di nuovo. Ad esempio:

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

Per fare questo senza setTimeout rimuovere l'animazione durante onmousedown, ed inserirlo durante onclick:

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

Yah, questo è lo stesso di quello che mi è venuto in mente. Ma mi piacerebbe fare a meno del setTimeout se possibile. –

+1

Ho aggiornato la mia risposta con un'alternativa che non usa setTimeout. – gilly3

0

Con il javascript, è anche possibile aggiungere (e quindi rimuovere) una classe CSS in cui viene dichiarata l'animazione. Capito quello che intendo ?

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

Un semplice ma efficace alternativa:

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/

Issues:
Non so se funziona su Firefox, perché l'animazione non sembra lavorare lì ...

+0

Funziona, ma per qualche motivo la regola di overflow viene ignorata .. Devo essere impostata su hidden ma dopo l'overflow di animazione mostra – Snowman

0

1) Aggiungere il nome di animazione al #box.trigger in css

#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-script non è possibile rimuovere la classe trigger.

3) Rimuovere il nome classe utilizzando il metodo setTimeOut.

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

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

4) Ecco lo DEMO.

1

Il clone funziona piuttosto bene in pausa Karaoke: Su IE11 ha dovuto forzare un reflow (versione più breve di R. Krupiński).

$('#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)); 
} 

oppure è possibile utilizzare il seguente:

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

Seguendo il suggerimento di https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Tips, rimuovere e quindi aggiungere la classe di animazione, utilizzando requestAnimationFrame per garantire che i processi di motore di rendering di entrambe le modifiche. Penso che sia più pulito dell'uso di setTimeout e gestisce la riproduzione di un'animazione prima del completamento della riproduzione precedente.

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

});

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

1

reimpostare il valore di prima. Utilizzare reflow per applicare la modifica senza l'utilizzo di timeout:

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>

In contrasto con la risposta accettata che raccomanda animationEnd, questo metodo reimposta l'animazione anche quando è ancora in corso. Questo potrebbe essere o potrebbe non essere quello che vuoi.


Un'alternativa sarebbe quella di creare un duplicato @keyframes animazione e passare tra i due:

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>

+0

nota: per https://stackoverflow.com/questions/21664940/force-browser-to-trigger -reflow-while-changing-css, potrebbe essere meglio usare eg 'void (box.offsetHeight);' invece, perché l'istruzione con accesso var e senza effetto può essere ottimizzata (e attiverà i linter per emettere avvisi come "Espressione imprevista". "in posizione di istruzione. - per gentile concessione di JSLint) – vaxquis

+0

inoltre, si noti che i reflows sono operazioni abbastanza "pesanti" (ad uso computazionale). – vaxquis

0

C'è un problema con l'utilizzo setTimeout() per rimuovere la classe e poi leggere 5 ms dopo?

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