在上一个完成后使用javascript回滚CSS动画 [英] Refire CSS animation with javascript after a previous one is complete

查看:392
本文介绍了在上一个完成后使用javascript回滚CSS动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用新的 animate()函数来重新播放CSS动画。我使用的是Chrome 48,但我不知道这是否可能现在。



动画应该是一个不断增长和缩小的广场。我已经尝试过几个事情,你可以看到,但没有工作:



  var elem = document.querySelector(。 document.addEventListener(click,function(){elem.classList.add(close); elem.animate(); // not working elem.animate(grow); // not working elem.animate [{transform:'scale(1)'},{transform:'scale(0)'}],1500); // not working});  

  .box {width:200px; height:200px;背景:#099;动画:grow 1s ease; transform-origin:0 0;}。close {animation:grow 1s ease reverse;} {关键帧增长{from {transform:scale(0) }到{transform:scale(1); }}  

 < div class =box> < / div>  



问题似乎是,第一个动画结束,元素的动画状态是完成(或类似的东西),所以当你改变动画属性,它仍然是完整的,它不会再次开始。因为第二个动画应该在事件后触发,所以它不能被迭代。



编辑:我注意到,当我在广场仍在增长的时候点击,



编辑2:我发现如果你只添加reverse属性,动画不会触发,但如果你将时间改为不同的值,

解决方案

你在问题​​的最后一段提到的是点上。一旦动画设置为元素并完全执行,浏览器/ UA将继续记住其状态。该动画无法重新启动(以相同或相反的方向),除非原始动画至少在一秒内删除。



为此,我们需要引入延迟(超时)或强制重绘,因为没有,如果我们在同一个阻塞调用中单独删除和添加类,UA将不会看到任何差异。



要重新启动相同的动画



当在文档中的任何位置单击时,要重新触发同一动画,只需删除现有动画的类,并在延迟之后重新添加它,如下面的代码段。



  var elem = document.querySelector(。box); document.addEventListener(click,function(e){refireAnim open);}); function refireAnim(anim){elem.classList.remove(anim); setTimeout(function(){elem.classList.add(anim);},0);}  

  .box {width:200px; height:200px;背景:#099; transform-origin:0 0;}。open {animation:grow 1s ease;} {关键帧增长{from {transform:scale(0) }到{transform:scale(1); }}  

 < div class =box open> ;< / div>  





$ b b

要在不同方向重新发射相同的动画:



要重新发射相同的动画,但方向不同,删除和添加动画的类后,延迟像上面的代码段,也改变方向。



  var elem = document.querySelector(。box)forward = true; document.addEventListener function(){refireAnim(open); if(forward){/ *根据状态改变方向* / elem.style [animation-direction] =reverse;} else {elem.style [animation ';';';';''= null;} forward =!forward; / *改变状态* /}); function refireAnim(anim){elem.classList.remove(anim); setTimeout(function(){elem.classList.add(anim);},0);}  

  .box {width:200px; height:200px;背景:#099; transform-origin:0 0;}。open {animation:grow 1s ease forward;} @ keyframes grow {from {transform:scale(0) }到{transform:scale(1); }}  

 < script src =https:// cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js\"> ;</script> ;<div class =box open>< / div>  



或者正如你所指出的,在删除课程后,再次添加。 (



  var elem = document.querySelector .box)forward = true; document.addEventListener(click,function(){refireAnim(open); if(forward){/ *根据状态改变方向* / elem.style [方向] =反向;} else {elem.style [动画方向] = null;} forward =!forward; / *改变状态* /}); function refireAnim(anim){elem.classList。 remove(anim); elem.clientHeight; elem.classList.add(anim);}  

  .box {width:200px; height:200px;背景:#099; transform-origin:0 0;}。open {animation:grow 1s ease forward;} @ keyframes grow {from {transform:scale(0) }到{transform:scale(1); }}  

 < script src =https:// cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js\"> ;</script> ;<div class =box open>< / div>  






到另一个:



创建两个类,其中一个用于打开动画,另一个用于关闭动画,



  var trigger = document.querySelector(#toggle),elem = document.querySelector(。box); trigger.addEventListener(click,function(){currState = elem.className.split()[1]; newState =(currState ==open)?关闭:open; switchAnim(currState,newState);}); function switchAnim(existingAnim,newAnim){elem.classList.remove(existingAnim); setTimeout(function(){elem.classList.add(newAnim);},0);}  

  .box {width:200px; height:200px;背景:#099; transform {origin:0};} {关闭} {关键帧} {关键帧}从{transform:scale(0); }到{transform:scale(1); }}  

 < input type =checkboxid = toggle/>< div class =box open>< / div>  


$ b

正如你在评论中指出的,你可以避免超时,而是在添加其他动画的类之前强制浏览器重新绘制。 (



  var trigger = document.querySelector #toggle),elem = document.querySelector(。box); trigger.addEventListener(click,function(){currState = elem.className.split()[1]; newState =(currState = =open)?close:open; switchAnim(currState,newState);}); function switchAnim(existingAnim,newAnim){elem.classList.remove(existingAnim); elem.clientHeight; elem.classList.add(newAnim);}  

  .box {width:200px; height:200px;背景:#099; transform {origin:0};} {关闭} {关键帧} {关键帧}从{transform:scale(0); }到{transform:scale(1); }}  

 < input type =checkboxid = toggle/>< div class =box open>< / div>  


$ b

避免闪光的另一种方法是(在短暂的时间内元素在再次动画之前恢复到其真实的高度和宽度)是使用像下面的代码段中的转换。



  var trigger = document.querySelector(#toggle),elem = document.querySelector(。box) ; trigger.addEventListener(click,function(){elem.classList.toggle(close); elem.classList.toggle(open);}); window.onload = function(){elem.classList。 toggle(close); elem.classList.toggle(open);}  

  .box {width:200px; height:200px;背景:#099; transform-origin:0 0; transition:all 1s;}。open {transform:scale(1);} close {transform:scale(0);}   < input type =checkboxid =toggle/>< div class =box close>< / div> code> 






- 在给定点处元素上存在任何动画:



复选框切换动画,但每当文档被点击时,



  var trigger = document.querySelector(#toggle),elem = document.querySelector(。box); document.addEventListener(click,function(e){if(e.target!= trigger){currState = elem.className.split()[1]; switchAnim(currState,currState); }})trigger.addEventListener(click,function(){if(trigger.checked)switchAnim(close,open); else switchAnim(open,close);}); function switchAnim existingAnim,newAnim){console.log(existingAnim); elem.classList.remove(existingAnim); setTimeout(function(){elem.classList.add(newAnim);},0);}  

  .box {width:200px; height:200px;背景:#099; transform {origin:0};} {关闭} {关键帧} {关键帧}从{transform:scale(0); }到{transform:scale(1); }}  

 < input type =checkboxid = togglechecked />< div class =box open>< / div>  

b $ b

I was trying to use the new animate() function to refire a CSS animation. I'm using Chrome 48 but I wonder if this is even possible right now.

The animation should be just a growing and shrinking square. I've tried several things, as you can see, but none worked:

var elem = document.querySelector(".box");

document.addEventListener("click", function() {
  elem.classList.add("close");
  elem.animate(); //not working
  elem.animate("grow"); //not working
  elem.animate([{
    transform: 'scale(1)'
  }, {
    transform: 'scale(0)'
  }], 1500); //not working
});

.box {
  width: 200px;
  height: 200px;
  background: #099;
  animation: grow 1s ease;
  transform-origin: 0 0;
}
.close {
  animation: grow 1s ease reverse;
}
@keyframes grow {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}

<div class="box"></div>

The problem seems to be that when the first animation ends, the animation state of the element is "complete" (or something like that) so when you change the animation property, it is still complete, and it doesn't begin again. As the second animation should fire after an event, it can't be iterated.

Edit: I noticed that this works when if I click while the square is still growing!

Edit2: I found out that if you just add the reverse property, the animation doesn't fire but if you change the time to a different value, or the animation name, it fires again!

解决方案

What you had mentioned in the last paragraph of your question is spot on. Once an animation is set to an element and has executed completely, the browser/UA would continue to remember its state. That animation cannot be restarted (either in the same or reverse direction) unless the original animation is removed atleast for a split second.

For this, we need to introduce a delay (time-out) or force a repaint because without that if we remove and add just the classes alone within the same blocking call then UA would not see any difference. It would continue to think that the animation was never removed.

For re-firing the same animation:

To re-fire the same animation again when the a click is made anywhere in the document, just remove the existing animation's class and add it back again after a delay like in the below snippet.

var elem = document.querySelector(".box");

document.addEventListener("click", function(e) {
  refireAnim("open");
});

function refireAnim(anim) {
  elem.classList.remove(anim);
  setTimeout(function() {
    elem.classList.add(anim);
  }, 0);
}

.box {
  width: 200px;
  height: 200px;
  background: #099;
  transform-origin: 0 0;
}
.open {
  animation: grow 1s ease;
}
@keyframes grow {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}

<div class="box open"></div>


For re-firing the same animation in different direction:

To re-fire the same animation again but in a different direction, remove and add the animation's class after a delay like in the above snippet and also change the direction.

var elem = document.querySelector(".box")
  forward = true;

document.addEventListener("click", function() {
  refireAnim("open");
  if (forward) { /* change the direction based on state */
  	elem.style["animation-direction"] = "reverse"; 
  }
  else {
  	elem.style["animation-direction"] = null;
  }  
  forward = !forward; /* change the state */
});

function refireAnim(anim) {
  elem.classList.remove(anim);
  setTimeout(function() {
    elem.classList.add(anim);
  }, 0);
}

.box {
  width: 200px;
  height: 200px;
  background: #099;
  transform-origin: 0 0;
}
.open {
  animation: grow 1s ease forwards;
}
@keyframes grow {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="box open"></div>

Or as you pointed out, force a repaint after the removal of the class but before its adding it again. (This seems to avoid the flash on toggle)

var elem = document.querySelector(".box")
  forward = true;

document.addEventListener("click", function() {
  refireAnim("open");
  if (forward) { /* change the direction based on state */
  	elem.style["animation-direction"] = "reverse"; 
  }
  else {
  	elem.style["animation-direction"] = null;
  }  
  forward = !forward; /* change the state */
});

function refireAnim(anim) {
  elem.classList.remove(anim);
  elem.clientHeight;
  elem.classList.add(anim);
}

.box {
  width: 200px;
  height: 200px;
  background: #099;
  transform-origin: 0 0;
}
.open {
  animation: grow 1s ease forwards;
}
@keyframes grow {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="box open"></div>


For toggling one animation to another:

Create two classes where one is for the open animation, another is for the close animation and toggle them on click such that there is a delay between removal of one class and addition of another.

var trigger = document.querySelector("#toggle"),
  elem = document.querySelector(".box");

trigger.addEventListener("click", function() {
  currState = elem.className.split(" ")[1];
  newState = (currState == "open") ? "close" : "open";
  switchAnim(currState, newState);
});

function switchAnim(existingAnim, newAnim) {
  elem.classList.remove(existingAnim);
  setTimeout(function() {
    elem.classList.add(newAnim);
  }, 0);
}

.box {
  width: 200px;
  height: 200px;
  background: #099;
  transform-origin: 0 0;
}
.open {
  animation: grow 1s ease;
}
.close {
  animation: grow 1s ease reverse forwards;
}
@keyframes grow {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}

<input type="checkbox" id="toggle" />
<div class="box open"></div>

As you had pointed out in comments, you could avoid the time-out and instead force the browser to do a repaint before adding the other animation's class also. (This seems to avoid the flash on toggle)

var trigger = document.querySelector("#toggle"),
  elem = document.querySelector(".box");

trigger.addEventListener("click", function() {
  currState = elem.className.split(" ")[1];
  newState = (currState == "open") ? "close" : "open";
  switchAnim(currState, newState);
});

function switchAnim(existingAnim, newAnim) {
  elem.classList.remove(existingAnim);
  elem.clientHeight;
  elem.classList.add(newAnim);
}

.box {
  width: 200px;
  height: 200px;
  background: #099;
  transform-origin: 0 0;
}
.open {
  animation: grow 1s ease;
}
.close {
  animation: grow 1s ease reverse forwards;
}
@keyframes grow {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}

<input type="checkbox" id="toggle" />
<div class="box open"></div>

The other way to avoid that flash (a brief period where the element reverts to its real height and width before being animated again) is to make use of transitions like in the below snippet.

var trigger = document.querySelector("#toggle"),
  elem = document.querySelector(".box");

trigger.addEventListener("click", function() {
  elem.classList.toggle("close");
  elem.classList.toggle("open");
});


window.onload = function() {
  elem.classList.toggle("close");
  elem.classList.toggle("open");
}

.box {
  width: 200px;
  height: 200px;
  background: #099;
  transform-origin: 0 0;
  transition: all 1s;
}
.open {
  transform: scale(1);
}
.close {
  transform: scale(0);
}

<input type="checkbox" id="toggle" />
<div class="box close"></div>


Re-firing whatever animation exists on the element at a given point:

The checkbox toggles the animation but whenever the document is clicked, whichever animation that is applicable depending on the checkbox's state will be re-fired.

var trigger = document.querySelector("#toggle"),
  elem = document.querySelector(".box");

document.addEventListener("click", function(e) {
  if (e.target != trigger) {
    currState = elem.className.split(" ")[1];
    switchAnim(currState, currState);
  }
})

trigger.addEventListener("click", function() {
  if (trigger.checked)
    switchAnim("close", "open");
  else
    switchAnim("open", "close");
});

function switchAnim(existingAnim, newAnim) {
  console.log(existingAnim);
  elem.classList.remove(existingAnim);
  setTimeout(function() {
    elem.classList.add(newAnim);
  }, 0);
}

.box {
  width: 200px;
  height: 200px;
  background: #099;
  transform-origin: 0 0;
}
.open {
  animation: grow 1s ease;
}
.close {
  animation: grow 1s ease reverse forwards;
}
@keyframes grow {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}

<input type="checkbox" id="toggle" checked/>
<div class="box open"></div>

这篇关于在上一个完成后使用javascript回滚CSS动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆