简体   繁体   English

如何检测CSS3动画或Web动画API所做的更改?

[英]How to detect changes made by CSS3 animation or web animations API?

How can I detect changes made by CSS3 animations or web animations ( Element.animate )?? 如何检测CSS3动画或Web动画( Element.animate )所做的更改?

(Sorry for my bad English! this is my first question in Stackoverflow) (对不起,我的英语不好!这是我在Stackoverflow中的第一个问题)

I know about MutationObserver, it responds only if I change the inline style or if I use requestAnimationFrame (since I change the inline style using it). 我知道MutationObserver,它仅在更改内联样式或使用requestAnimationFrame时才响应(因为我使用它更改了内联样式)。 But if I use CSS3 animations or Web animations, MutationObserver doesn't respond since they don't change the inline style. 但是,如果我使用CSS3动画或Web动画,则MutationObserver不会响应,因为它们不会更改内联样式。

See this... There are two divs here... div1, div2. 看到这个...这里有两个divs ... div1,div2。 div1's position will change when div2's position changes. div2的位置更改时div1的位置也会更改。 But this happens only if I use requestAnimationFrame as I said before. 但这仅在我使用前面所说的requestAnimationFrame时发生。

My question is how can I do this for css3 animations and web animations (Element.animate)? 我的问题是如何为CSS3动画和Web动画(Element.animate)执行此操作?

 const div1 = document.getElementById('div1'); const div2 = document.getElementById('div2'); /***** Add mutation observer to detect change *****/ const mutation = new MutationObserver(mutations => { div1.style.left = div2.style.left; }); mutation.observe(div2, { attributes: true }); /***** Animation with css *****/ function cssAnimation() { div2.style.animation = 'anim 1.5s linear'; } /***** Animation with web animations *****/ function webAnimation() { div2.animate({ left: [0, '500px'] }, { duration: 1500, easing: 'linear' }); } /*****Animation with requestAnimationFrame ******/ // Current left position of div2 const left = 0; function requestAnimation() { // Increase left position 5px per keyframe div2.style.left = `${(left += 5)}px`; // Increase left position until it reaches to 500px if (left < 500) { requestAnimationFrame(requestAnimation); } } function clearAnimations() { left = 0; div2.style.left = 0; div2.style.animation = 'unset'; } 
 @keyframes anim { from { left: 0; } to { left: 500px; } } #div1 { background: orange; width: 100px; height: 100px; position: absolute; top: 200px; } #div2 { background: lightgreen; width: 100px; height: 100px; position: absolute; top: 100px; } 
 <div id="buttons"> <h3>Animate with...</h3> <button onclick='cssAnimation()'>Css3</button> <button onclick="requestAnimation()">request animation frame</button> <button onclick="webAnimation()">web animations api</button> <button id="clear" onclick="clearAnimations()">Clear</button> </div> <div id="div1"> Div1 </div> <div id="div2"> div2 </div> 

Both CSS Animations and Web Animations are based on the principle that you delegate the playback of the animation to the browser. CSS动画和Web动画均基于将动画回放委派给浏览器的原理。 That allows the browser to run the animation on a separate thread or process when possible, so that it runs smoothly. 这样,浏览器就可以在可能的情况下在单独的线程或进程上运行动画,从而使其流畅运行。 Updating style from JavaScript on each frame is best avoided where possible. 尽可能避免在每帧上从JavaScript更新样式。

In your example, can you simply run the animation on both elements at the same time? 在您的示例中,您可以简单地同时在两个元素上运行动画吗? Web Animations, at least, allows synchronizing the animations. 至少,Web动画允许同步动画。

When the remainder of the Web Animations API is shipped, it will be much easier to duplicate animations from one element and apply them to another but for now you would need to call animate twice. Web动画API的其余部分交付时,从一个元素复制动画并将它们应用于另一个元素会容易得多,但是现在您需要调用两次animate

As others have pointed out, it is possible to observe significant moments in the playback of animations (when they start, finish, repeat etc.) but there is no event that runs on each frame. 正如其他人指出的那样,可以观察到动画回放中的重要时刻(当它们开始,完成,重复等时),但是每一帧都没有事件在运行。 If you want to perform and action on each frame you need to use requestAnimationFrame . 如果要在每个帧上执行操作,则需要使用requestAnimationFrame

If you pass div2 to getComputedStyle in requestAnimationFrame you will get the animated style for that frame which you can then apply to div1 . 如果将div2传递给requestAnimationFrame getComputedStyle ,您将获得该帧的动画样式,然后可以将其应用于div1 (That is, reading div2.style.left will only give you the style specified via the style attribute but getComputedStyle(div2).left will give you the animated style including style changes from CSS animations and Web Animations). (也就是说,阅读div2.style.left只会为您提供通过style属性指定的stylegetComputedStyle(div2).left则会为您提供动画样式,包括CSS动画和Web动画的样式更改)。 But, again, that will lead to poor performance and the two animations will not necessarily be synchronized since the CSS animation or Web animation may run on a different thread or process. 但是,这又将导致性能下降,并且两个动画不一定同步,因为CSS动画或Web动画可能在不同的线程或进程上运行。

For css animations, you have the animationstart and animationend events that could help you with what you are trying to achieve. 对于CSS动画,您具有animationstart和animationend事件,它们可以帮助您实现所要达到的目标。 However, there is no animationchange or animationupdate event, and it is this way, as far as I know, by design. 但是,没有动画更改动画更新事件,据我所知,这种方式是设计使然。 Without events during the animation happening, it is possible to reach full hardware acceleration, with the interpolation computations done directly in the GPU. 如果动画期间没有事件发生,则可以直接在GPU中完成插值计算,从而达到完全的硬件加速。 So, be aware that while you might be able to mimic what an animationchange event would do via animationstart, animationend and requestAnimationFrame, this is probably going to involve a performance penalty. 因此,请注意,虽然您可能可以通过animationstart,animationend和requestAnimationFrame来模拟animationchange事件将执行的操作,但这可能会涉及性能损失。

You're over complicating things. 您已经使事情变得复杂了。 But to listen for animation changes you can listen on these events instead of the mutation observer. 但是,要收听动画更改,您可以侦听这些事件,而不是变异观察者。

animationstart //will fire has soon as the animation starts
animationiteration //will fire if the same animation is looped can be infinity or more then 2
animationend // will fire when the animations have ended

also please use translate instead of animating the left property. 也请使用translation而不是为left属性设置动画。

You can use requestAnimationFrame and window.getComputedStyle() to get current animated styles during the animation, note, included fill:"forward" at Element.animate() call 您可以使用requestAnimationFramewindow.getComputedStyle()来获取动画期间的当前动画样式,注释,并在Element.animate()调用中包括fill:"forward"

 var div1 = document.getElementById("div1"); var div2 = document.getElementById("div2"); /***** Add mutation observer to detect change *****/ var mutation = new MutationObserver(function(mutations) { div1.style.left = div2.style.left; }); mutation.observe(div2, { attributes: true }); /***** Animation with css *****/ function cssAnimation() { div2.style.animation = "anim 1.5s linear forwards"; let animationFrame; function getCurrentStyles() { console.log(window.getComputedStyle(div2).left); animationFrame = requestAnimationFrame(getCurrentStyles) } getCurrentStyles(); div2.addEventListener("animationend", () => cancelAnimationFrame(animationFrame)); } /***** Animation with web animations *****/ function webAnimation() { let animationFrame; function getCurrentStyles() { console.log(window.getComputedStyle(div2).left); animationFrame = requestAnimationFrame(getCurrentStyles) } getCurrentStyles(); div2.animate({ left: [0, "500px"] }, { duration: 1500, fill: "forwards", easing: "linear" }).onfinish = function() { cancelAnimationFrame(animationFrame); console.log(window.getComputedStyle(div2).left); }; } /*****Animation with requestAnimationFrame ******/ //Current left position of div2 var left = 0; function requestAnimation() { //Increase left position 5px per keyframe div2.style.left = `${(left += 5)}px`; console.log(window.getComputedStyle(div2).left); //Increase left position until it reaches to 500px if (left < 500) { requestAnimationFrame(requestAnimation); } } function clearAnimations() { left = 0; div2.style.left = 0; div2.style.animation = "unset"; } 
 @keyframes anim { from { left: 0; } to { left: 500px; } } #div1 { background: orange; width: 100px; height: 100px; position: absolute; top: 200px; } #div2 { background: lightgreen; width: 100px; height: 100px; position: absolute; top: 100px; } 
 <div id="buttons"> <h3>Animate with...</h3> <button onclick='cssAnimation()'>Css3</button> <button onclick="requestAnimation()">request animation frame</button> <button onclick="webAnimation()">web animations api</button> <button id="clear" onclick="clearAnimations()">Clear</button> </div> <div id="div1"> Div1 </div> <div id="div2"> div2 </div> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM