Як повторно запустити анімацію CSS WebKit через JavaScript?


77

Отже, у мене є таке -webkit-animationправило:

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

І деякі CSS, що визначають деякі правила анімації на моєму box:

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

Я можу shakeзробити #boxтак:

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

Але згодом я знову не можу його похитнути.

Це трясе лише один раз:

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

Як я можу повторно запустити CSS-анімацію через JavaScript, не використовуючи тайм-аути чи кілька анімацій?


jQuery чи подібна бібліотека - варіант? Ви, мабуть, побачите кращу підтримку браузера.
Surreal Dreams

jQuery доступний, але насправді не застосовується в моєму випадку. Мені не потрібна інша підтримка браузера, оскільки вона працюватиме лише в Adobe Air. Я намагаюся дотримуватися CSS-анімації замість JavaScript.
Девід Мердок,



Відповіді:


94

Я знайшов відповідь на основі вихідного коду та прикладів на сторінці github перехідних тестів CSS3 .

В основному, анімація CSS має animationEndподію, яка запускається після завершення анімації.

Для браузерів webkit ця подія називається “ webkitAnimationEnd”. Отже, для того, щоб скинути анімацію після її виклику, потрібно додати прослуховувач подій до елемента animationEndподії.

У простому ванільному 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.
};

та з jQuery:

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

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

Вихідний код для тестів переходів CSS3 (згаданий вище) має наступний supportоб'єкт, який може бути корисним для переходів, перетворень та анімації CSS у різних браузерах.

Ось код підтримки (переформатований):

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

Я не додав код для виявлення властивостей "анімації" для кожного браузера. Я зробив цю відповідь “wiki спільноти” і залишаю це вам. :-)


цитований вихідний код переміщено на github.com/louisremi/jquery.transition.js
Том Сардуй

2
Примітка: код у репозиторії github змінився після цієї відповіді; код там і код тут зараз абсолютно різні.
Девід Мердок,

1
Зверніть увагу, що якщо існує правило CSS, яке призначає анімацію об’єкту, установка на ''це змусить його успадковуватись від правила CSS, у такому випадку необхідно встановити для нього значення none.
user202729

13

Спочатку потрібно видалити анімацію, а потім додати її знову. Наприклад:

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

Для цього без setTimeout видаліть анімацію під час onmousedownта додайте її під час onclick:

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

Так, це те саме, що я придумав. Але я хотів би обійтися без setTimeout, якщо це можливо.
Девід Мердок,

1
Я оновив свою відповідь альтернативою, яка не використовує setTimeout.
gilly3

7

Відповідно до пропозиції https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Tips , видаліть і додайте клас анімації, використовуючи requestAnimationFrame, щоб переконатися, що механізм візуалізації обробляє обидві зміни. Я думаю, що це чистіше, ніж використання setTimeout, і обробляє відтворення анімації до завершення попередньої гри.

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

});

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


6

Проста, але ефективна альтернатива:

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');

});​

Демо:
http://jsfiddle.net/5832R/2/

Проблеми:
Я не знаю, чи працює це у Firefox, бо анімація там, здається, не працює ...


Це працює, але з якихось причин правило переповнення ігнорується .. У мене встановлено значення "приховане", але після переповнення анімації відображається
Сніговик

1

Клон працює досить добре на призупиненому караоке: на IE11 довелося змусити перепрофілювати (коротша версія Р. Крупінського).

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

або ви можете використовувати наступне:

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

1

Спершу скиньте значення. Використовуйте перекладання, щоб застосувати зміну без використання часу очікування:

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>

На відміну від прийнятої відповіді, яка рекомендує animationEnd, цей метод скидає анімацію навіть тоді, коли вона все ще триває. Це може бути чи не те, що ти хочеш.


Альтернативою може бути створення дубльованої @keyframesанімації та перемикання між ними:

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>


Примітка: згідно stackoverflow.com/questions/21664940/… , можливо, краще використовувати, наприклад, void( box.offsetHeight);замість цього, тому що оператор з доступом var і без ефекту може бути оптимізований (і буде запускати лінтери для Unexpected expression '.' in statement position.видачі попереджень, таких як - люб'язно надано JSLint)

також зауважте, що перепланування є досить "важкими" (обчислювально інтенсивними) операціями.

1

Чи є проблема з використанням setTimeout()для видалення класу, а потім прочитання його через 5 мс?

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

0

За допомогою свого javascript ви також можете додати (а потім видалити) клас CSS, в якому оголошено анімацію. Розумієте, що я маю на увазі?

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

0

1) Додайте назву анімації до #box.triggercss

#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) У Java-скрипті ви не можете видалити клас trigger.

3) Видаліть назву класу за допомогою setTimeOutметоду.

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

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

4) Ось ДЕМО .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.