【问题标题】:How do I re-trigger a WebKit CSS animation via JavaScript?如何通过 JavaScript 重新触发 WebKit CSS 动画?
【发布时间】:2011-06-15 10:09:10
【问题描述】:

所以,我有这个-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 动画?

【问题讨论】:

标签: javascript css html animation webkit


【解决方案1】:

我根据CSS3 transition tests github page的源代码和示例找到了答案。

基本上,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 transition tests(如上所述)的源代码具有以下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
  • 注意:自此答案以来,github repo 中的代码已更改;那里的代码和这里的代码现在完全不同了。
  • 请注意,如果有一个 CSS 规则将动画分配给对象,将其设置为 '' 将使其继承 CSS 规则,在这种情况下需要将其设置为 @987654332 @.
【解决方案2】:

你必须先移除动画,然后再添加。例如:

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。
  • 我已经用不使用 setTimeout 的替代方法更新了我的答案。
【解决方案3】:

按照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/

【讨论】:

    【解决方案4】:

    一个简单但有效的替代方案:

    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,因为动画似乎在那里不起作用......

    【讨论】:

    • 这行得通,但由于某种原因溢出规则被忽略了..我将它设置为隐藏但在动画溢出显示之后
    【解决方案5】:

    克隆在暂停的卡拉 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)); 
    }
    

    【讨论】:

      【解决方案6】:

      首先重置值。使用回流来应用更改而不使用超时:

      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 访问权限且没有效果的语句可能会被优化(并且会触发 linter 发出警告,如 Unexpected expression '.' in statement position. - 由 JSLint 提供)
      • 另外,请注意回流是相当“繁重”(计算密集型)的操作。
      【解决方案7】:

      使用setTimeout() 删除类,然后在 5 毫秒后读取它有问题吗?

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

      【讨论】:

        【解决方案8】:

        使用您的 javascript,您还可以添加(然后删除)一个声明动画的 CSS 类。明白我的意思了吗?

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

        【讨论】:

          【解决方案9】:

          1) 在css中为#box.trigger添加动画名称

          #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-script 中,您不能删除类 trigger

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

          $(document).ready(function(){
              $('#shake-the-box').click(function(){
          
              $('#box').addClass('trigger');
              setTimeout(function(){
                  $("#box").removeClass("trigger")},500)        
              });
          }); 
          

          4) 这是DEMO

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-07-28
            • 2019-01-03
            • 1970-01-01
            • 2018-07-17
            • 2016-04-29
            • 1970-01-01
            • 2017-12-04
            相关资源
            最近更新 更多