使用 CSS 动画(例如 @keyframes),“重新启动”它并不像您想象的那么容易。
假设您将其设置为运行一次
.run-animation {
animation: my-fancy-animation 5s 1;
}
您可以在您的徽标上运行它
<h1 id="logo" class="run-animation">
Fancy Logo
</h1>
然后出于某种原因,您希望该动画再次运行,也许是在点击时。您可能认为 CSS 提供了一种方法来再次启动它,但据我所知,它没有。您甚至可以尝试通过 JavaScript(jQuery)删除和重新添加该类名
$("#logo").click(function() {
// not gonna work
$(this).removeClass("run-animation").addClass("run-animation");
});
如果您在删除和重新添加类之间设置一个很小的延迟(例如 setTimeout()
),它将起作用,但我认为不必说这不是理想的。您真正需要做的是完全从页面中删除元素并重新插入它。作为使用 jQuery 的快速演示,我们将克隆它,将其插入其自身之后,然后删除原始元素。
$("#logo").click(function() {
var el = $(this),
newone = el.clone(true);
el.before(newone);
$("." + el.attr("class") + ":last").remove();
});
或仅使用 JavaScript 的基础知识
const el = this;
var newone = elm.cloneNode(true);
elm.parentNode.replaceChild(newone, elm);
任何类型的事件都存在同样的问题。假设您有一个希望立即运行的动画,然后在 :hover
上再次运行。同样的问题,它不会再次运行。Oli Studholme 对此进行了一些有趣的研究。一种解决方法是使用两个动画,这两个动画完全相同,除了它们的名称,然后您可以切换在 :hover
事件(或任何事件)中使用哪个动画,它将起作用。
img {animation: spin-cat-1 2s;}
img:active {animation: spin-cat-2 2s;}
@keyframes spin-cat-1 {50%{transform:rotateY(180deg);}}
@keyframes spin-cat-2 {50%{transform:rotateY(180deg);}}
CSS 预处理器可以通过导入代码块来帮助简化维护,因此您只需在一个地方维护它,但这最终会造成膨胀。不幸的是,您也不能在一个声明中定义多个关键帧动画名称,这也很有用(不仅限于此,想想更复杂的动画,您可以在基本关键帧动画的基础上重写某些关键帧)。
Oli 还 尝试了各种其他技术 来使其工作,例如更改持续时间、延迟和迭代次数而不是更改名称,但在我看来,所有这些都比更改名称更糟糕。
更新:另一种重新启动 CSS 动画的 JavaScript 方法
在删除和添加类名之间触发回流。例如
// retrieve the element
element = document.getElementById("logo");
// reset the transition by...
element.addEventListener("click", function(e) {
e.preventDefault;
// -> removing the class
element.classList.remove("run-animation");
// -> triggering reflow /* The actual magic */
// without this it wouldn't work. Try uncommenting the line and the transition won't be retriggered.
// Oops! This won't work in strict mode. Thanks Felis Phasma!
// element.offsetWidth = element.offsetWidth;
// Do this instead:
void element.offsetWidth;
// -> and re-adding the class
element.classList.add("run-animation");
}, false);
其他 JavaScript
仅供参考,您还可以通过 JavaScript 影响 CSS 动画的播放状态,例如暂停和重新启动它。
element.style.animationPlayState="paused";
element.style.animationPlayState="running";
// Vendor prefixed in old browsers
// element.style.webkitAnimationPlayState="paused";
// element.style.webkitAnimationPlayState="running";
有趣的是,CSS 动画的自然结束不会将播放状态设置为“暂停”。您必须自己执行此操作。假设您希望在每次悬停时重新启动动画,并且您很乐意使用 jQuery 来执行此操作……
$("#thing").hover(function() {
this.style.animationPlayState = "running";
$(this).on('animationEnd', function() {
this.style.animationPlayState = "paused";
});
});
请注意,您必须监视 AnimationEnd
事件的触发以将其设置回“暂停”,否则它将无法正确重新启动。
您在代码的最后一行做了什么?您只是尝试删除元素吗?不能通过 el.remove() 完成吗?
您现在有两个具有相同类名的元素,因此使用“el.remove”将删除这两个元素,因此您需要指定它需要删除最后一个元素。
我认为这是正确的哈
不可能,因为 el == $(this)。据我所见,它没有被操作
不错的帖子,Chris!
Paul,是的,可以通过以下方式简化……
http://jsfiddle.net/t3EaG/
更简洁
$(this).replaceWith($(this).clone());
我的意思是 $(this).replaceWith($(this).clone(true));
我想到过在元素上使用 insertBefore 来重新插入它,但那不起作用。不过有一件事,演示在 h1 元素而不是类上使用了动画,因此删除和替换类不起作用……
嗯……一种无 JS 的方法是使用过渡而不是动画,因为这些动画适用于悬停和活动,但这显然限制了您
无论如何,对于这个简单的动画来说,这是一种权宜之计;)
要重新启动动画,只需用 setTimeout() 包装 addClass 方法即可。类似于此事件处理程序
这也是我认为问题所在。在同一个执行周期(在本例中为您的事件处理程序)中删除和添加类名会导致 DOM 一旦 JavaScript 产生就没有任何变化。
setTimeout 将导致 JavaScript 在删除类名和重新添加类名之间产生,这允许浏览器注意到 DOM 操作并对其进行操作。
您实际上不需要包装 addClass 方法,您只需在 onclick 处理程序中为 $(this) 创建一个闭包并在 setTimeout 调用中引用它(例如 clamster 评论中的 elem 变量),因此如果您将 $(this) 分配给 elem,您仍然可以使用 jQuery removeClass 和 addClass。
另一种使用 addClass/removeClass 的方法是在调用之间强制回流,我认为这比 setTimeout 好一点
编辑注:Jorge Antunes 写信说这非常有效,并提供了一个 CodePen 演示。
Jesper,我同意它更好,但文章中说这种方法不起作用,不是吗?
您可以在动画结束时('webkitAnimationEnd')删除类名,然后在需要时(例如单击或任何事件)再次添加它。http://jsfiddle.net/nimbu/vxcYJ/
但如果它是无限动画呢?
我不确定为什么要重新启动无限动画 :/
无论如何,您需要从样式中删除 webkitAnimation 属性,然后延迟一段时间后再重新设置它才能使其启动。
暂停动画无论如何都包含在 animation-play-state 属性中。
只想说,如果您希望取消无限重复的事件,您可以检查此事件 ‘webkitAnimationIteration’,该事件在动画迭代次数超过 1 时触发。
这简单而优雅——太棒了。
如果您无论如何都要使用 jQuery,为什么不直接在 jQuery 中完成整个动画,这样会跨浏览器兼容?
当然可以。有一些考虑因素,具体取决于实际用例,因此很难进行理论上的辩论。它们都可以做对方做不到的事情。基于 JavaScript 的动画具有更深层的支持,但 CSS 动画通常更流畅,并且可以进行硬件加速。
没错,Chriss,但您在这里使用的是特定于供应商的动画,无论是否硬件加速,您仍然需要为不支持使用 CSS 的动画的浏览器提供后备方案,因此您不妨在 jQuery 中执行此操作,除非您采用功能检测方式并在这种情况下针对非 WebKit 浏览器。
据我所知,jQuery/Javascript 动画比 CSS3 动画更流畅……
争论还在继续!这实际上也是我的问题。为什么开始混合使用 CSS 动画和 JavaScript 动画?感觉将来维护起来会很麻烦。
我认为坚持使用其中一种会更容易,并且由于 CSS 还没有完全准备好(浏览器支持、无法重新启动动画),所以还是坚持使用 JavaScript 吧。
Safari 和 Chrome 上动画很流畅,但在 IE 8 上不流畅。不过我还没有在 Firefox 上尝试过。
我相信这是因为 IE8 不支持 CSS 动画。
非常有用,谢谢。
你好,
不久前我遇到了这个问题,我的解决方法是先移除类,然后设置一个 0ms 的计时器来重新添加它。
$('something').removeClass('anim').animate({'nothing':null}, 1, function () {
$(this).addClass('anim');
});
简单有效!
我将把“重新启动 CSS 动画”翻译成我的语言土耳其语。
从头开始重新播放 CSS 动画最简单的方法是将元素放置在主包装器中。
function Replay(){
var container = document.getElementById(“wrapper”);
var content = container.innerHTML;
container.innerHTML= content;
console.log(“replay”);
}
我遇到了 IE11 关键帧动画问题,你这里也遇到了同样的问题,基本上没有任何动画播放 :(
我的 jQuery 知识几乎为零。你上面做的事情非常棒,完美无缺,唯一的问题是我需要它定时,例如,在 3 秒后移除元素,然后在 40 秒后再次添加它。我该如何操作呢?