如何通过JavaScript重新触发WebKit CSS动画?


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

如何通过JavaScript重新触发CSS动画而不使用超时或多个动画?


jQuery或类似的库是一个选择吗?您可能会看到更好的浏览器支持。
超现实主义之梦

jQuery可用,但不适用于我的情况。我不需要其他浏览器支持,因为它将仅在Adobe Air中运行。我正在尝试使用CSS动画而不是JavaScript。
David Murdoch



Answers:


94

我在CSS3转换测试github页面上根据源代码和示例找到了答案。

基本上,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”,并留给您。:-)



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 2011年

7

按照https://developer.mozilla.org/zh-CN/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上运行,因为该动画似乎在那里不起作用...


这可行,但是由于某种原因,溢出规则被忽略了。我将其设置为隐藏,但是在动画溢出显示之后
Snowman 2012年

1

在暂停的卡拉OK上,克隆效果非常好:在IE11上必须进行重排(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)); 
}

或者您可以使用以下命令:

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.linter发出警告,例如-由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.trigger在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)在Java脚本中,您无法删除该类trigger

3)使用setTimeOut方法删除类名。

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

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

4)这是演示

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.