如何使用JavaScript暂停和恢复CSS3动画?

61

我尝试通过谷歌和这个论坛寻找解决我的问题的方法,但到目前为止没有运气。我想通过点击图片来暂停我的CSS3动画(图片幻灯片),并且也可以通过点击图片恢复到相同的动画。

我知道如何暂停幻灯片,并且我曾经能够恢复一次,但是如果尝试暂停和恢复多于一次,则会停止工作。以下是我的代码示例:

<!DOCTYPE html>
<html>

<head>
<title></title>
<style type="text/css">
.pic {
    position: absolute;
    opacity: 0;
}

#pic1 {
    -webkit-animation: pic1 4s infinite linear;
}

#pic2 {
    -webkit-animation: pic2 4s infinite linear;
}

@-webkit-keyframes pic1 {
    0%   {opacity: 0;}
    5%   {opacity: 1;}
    45%  {opacity: 1;}
    50%  {opacity: 0;}
    100% {opacity: 0;}
}

@-webkit-keyframes pic2 {
    0%   {opacity: 0;}
    50%  {opacity: 0;}
    55%  {opacity: 1;}
    95%  {opacity: 1;}
    100% {opacity: 0;}
}
</style>

<script type="text/javascript">
function doStuff(){
    var pic1 = document.getElementById("pic1");
    var pic2 = document.getElementById("pic2");

    pic1.style.webkitAnimationPlayState="paused";
    pic2.style.webkitAnimationPlayState="paused";

    pic1.onclick = function(){
        pic1.style.webkitAnimationPlayState="running";
        pic2.style.webkitAnimationPlayState="running";
    }

    pic2.onclick = function(){
        pic1.style.webkitAnimationPlayState="running";
        pic2.style.webkitAnimationPlayState="running";
    }
}
</script>
</head>  

<body>
    <img id="pic1" class="pic" src="photo1.jpg" />
    <img id="pic2" class="pic" src="photo2.jpg" onclick="doStuff()" />
</body>                                                                

</html>

我不想使用任何JS库(例如jQuery)或其他外部解决方案。

我猜测在doStuff函数内的函数仍在运行,这就是为什么pauseresume只能工作一次的原因。

有没有办法在点击一次后清除这些函数?或者我是完全错误地尝试做这个?感谢您的帮助。:)

5个回答

171

我发现使用CSS类更容易实现。通过这种方式,您可以为每个浏览器使用不同的前缀。

.paused{
    -webkit-animation-play-state:paused;
    -moz-animation-play-state:paused;
    -o-animation-play-state:paused; 
    animation-play-state:paused;
}

那么你只需要将这个类添加或删除到要动画化的元素上,就可以暂停/恢复动画。


@nq1 CSS是实现这个功能的正确方法。可以使用JavaScript来添加类别。与被接受的答案不同,这个解决方案也是跨浏览器兼容的。 - Matt
这似乎是更好的解决方案,但我无法让它工作。它需要动画是“无限”的吗? - Nateous
2
虽然这是老问题,但是@Nate和其他人需要知道。在每一行代码后面添加!important。CSS 遵循特定性规则,规则越具体,属性就越突出。animation-play-state: paused !important; 可以解决这个“问题”(这是 CSS 的设计原则,但在这里却成了问题)。这可能对 Luis 有效,因为他进行了简单的测试或者没有出现特定性“冲突”。 - Regular Jo
最好重新排列CSS,这样就不必使用“!important”,因为这会破坏很多其他东西,尽管在这种情况下可以辩称使用它,因为它会暂停动画。 - Nateous
更简单、更清晰、更好地分配责任。这应该放在最上面。CSS类应该尽可能地包装所有样式更改,通过操纵何时何地使用哪些类来实现JS与样式的交互。 - DanteTheSmith

38

以下是使用 JavaScript 的解决方案:

var imgs = document.querySelectorAll('.pic');

for (var i = 0; i < imgs.length; i++) {
  imgs[i].onclick = toggleAnimation;
  imgs[i].style.webkitAnimationPlayState = 'running';
}

function toggleAnimation() {
  var style;
  for (var i = 0; i < imgs.length; i++) {
    style = imgs[i].style;
    if (style.webkitAnimationPlayState === 'running') {
      style.webkitAnimationPlayState = 'paused';
      document.body.className = 'paused';
    } else {
      style.webkitAnimationPlayState = 'running';
      document.body.className = '';
    }
  }
}
.pic {
  position: absolute;
  opacity: 0;
}

#pic1 {
  -webkit-animation: pic1 4s infinite linear;
}

#pic2 {
  -webkit-animation: pic2 4s infinite linear;
}

@-webkit-keyframes pic1 {
  0% {
    opacity: 0;
  }
  5% {
    opacity: 1;
  }
  45% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}

@-webkit-keyframes pic2 {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 0;
  }
  55% {
    opacity: 1;
  }
  95% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

.paused {
  background-color: #ddd;
}
<img id="pic1" class="pic" src="http://placehold.it/200x200/ff0000/ffffff">
<img id="pic2" class="pic" src="http://placehold.it/200x200/ff00ff/ffffff">

jQuery 解决方案(更短更易读):

var imgs = $('.pic'),
  playState = '-webkit-animation-play-state';

imgs.click(function() {
  imgs.css(playState, function(i, v) {
    return v === 'paused' ? 'running' : 'paused';
  });
  $('body').toggleClass('paused', $(this).css(playState) === 'paused');
});
.pic {
  position: absolute;
  opacity: 0;
}

#pic1 {
  -webkit-animation: pic1 4s infinite linear;
}

#pic2 {
  -webkit-animation: pic2 4s infinite linear;
}

@-webkit-keyframes pic1 {
  0% {
    opacity: 0;
  }
  5% {
    opacity: 1;
  }
  45% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}

@-webkit-keyframes pic2 {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 0;
  }
  55% {
    opacity: 1;
  }
  95% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

.paused {
  background-color: #ddd;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id="pic1" class="pic" src="http://placehold.it/200x200/ff0000/ffffff">
<img id="pic2" class="pic" src="http://placehold.it/200x200/ff00ff/ffffff">


请问是否可以检测暂停时剩余的时间?谢谢。 - kabrice

10

这是对Luis Hijarrubia所给答案的扩展说明。

.pause {
   -webkit-animation-play-state: paused !important; 
   -moz-animation-play-state: paused !important; 
   -o-animation-play-state: paused !important;
    animation-play-state: paused !important;
}

在我的页面中,我触发了父元素的类变化。我只想旋转内部的图像。但是由于我没有使用hover,添加paused类对动画状态没有任何影响。

使用!important确保这些值被新添加的CSS值覆盖。


3
为了澄清,这是由于CSS特异性导致的。像Sime所回答的那样直接向元素添加属性的脚本不会有这个问题,因为“内联”样式默认情况下会覆盖样式表中的规则。https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity - xec
这是由你的HTML和CSS引起的特定问题。最好将其作为评论,它并没有回答实际问题。 - T J
如果还没有人回答,我来发表我的答案。在我的情况下,我需要暂停几个同时进行的动画,并发现这是最简单的方法。它还允许您添加像.pause:hover这样的效果,如果需要的话。 - Regular Jo

1
var e = document.getElementsById("Your_Id");


e.addEventListener("animationstart", listener, false);
e.addEventListener("animationend", listener, false);
e.addEventListener("animationiteration", listener, false);


function listener(e) {  alert("Your POSITION parameter:" + .target.style.position);
  switch(e.type) {
    case "animationstart":
      d = "Started: elapsed time is " + e.elapsedTime;
      break;
    case "animationend":
      d = "Ended: elapsed time is " + e.elapsedTime;
      break;
    case "animationiteration":
      d= "New loop started at time " + e.elapsedTime;  alert("pausing for 1 seconddddddd!!!!!!!"); e.target.style.animationPlayState = "paused";        window.setTimeout(function(){e.target.style.animationPlayState = "running";}, 1000);
      break;
  }
}

-1

我还没有测试过,但或许可以尝试这样做?

<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
.pic {   position: absolute;opacity: 0;  }
.pic1 {  -webkit-animation: pic1 4s infinite linear;   }
.pic2 {  -webkit-animation: pic2 4s infinite linear;   }
@-webkit-keyframes pic1 {  0%   {opacity: 0;}
                           5%   {opacity: 1;}
                           45%  {opacity: 1;}
                           50%  {opacity: 0;}
                           100% {opacity: 0;}    }
@-webkit-keyframes pic2 {  0%   {opacity: 0;}
                           50%  {opacity: 0;}
                           55%  {opacity: 1;}
                           95%  {opacity: 1;}
                           100% {opacity: 0;}    }
</style>
<script type="text/javascript">
function doStuff(){
    var pic1 = document.getElementById("pic1");
    var pic2 = document.getElementById("pic2");

    pic1.className="pic paused";
    pic2.className="pic paused";

    pic1.onclick = function(){
       pic1.className="pic pic1";
       pic2.className="pic pic2";
    }
    pic2.onclick = function(){
       pic1.className="pic pic1";
       pic2.className="pic pic2";
    }
}
</script>
</head>  
<body>
    <img id="pic1" class="pic pic1" src="photo1.jpg" />
    <img id="pic2" class="pic pic2" src="photo2.jpg" onclick="doStuff()" />
</body>                                                                 
</html>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接