如何检测 CSS3 动画或网络动画 API 所做的更改?
How to detect changes made by CSS3 animation or web animations API?
如何检测 CSS3 动画或网络动画 (Element.animate
) 所做的更改??
(抱歉我的英语不好!这是我在 Whosebug 中的第一个问题)
我知道 MutationObserver,只有当我更改内联样式或使用 requestAnimationFrame
时它才会响应(因为我使用它更改了内联样式)。但是,如果我使用 CSS3 动画或 Web 动画,MutationObserver 不会响应,因为它们不会更改内联样式。
看到这个...这里有两个 div...div1,div2。当div2 的位置改变时,div1 的位置也会改变。但只有当我像我之前所说的那样使用 requestAnimationFrame 时才会发生这种情况。
我的问题是如何为 css3 动画和网络动画 (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>
对于 css 动画,您有 animationstart 和 animationend 事件可以帮助您实现您想要实现的目标。但是,没有 animationchange 或 animationupdate 事件,据我所知,这是设计使然。如果动画期间没有事件发生,则可以实现完全硬件加速,插值计算直接在 GPU 中完成。因此,请注意,虽然您可以通过 animationstart、animationend 和 requestAnimationFrame 模拟 animationchange 事件的作用,但这可能会影响性能。
你把事情复杂化了。但是要监听动画变化,您可以监听这些事件而不是变异观察器。
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
也请使用翻译而不是动画左侧 属性。
您可以使用 requestAnimationFrame
和 window.getComputedStyle()
在动画过程中获取当前动画样式,请注意,包含 fill:"forward"
在 Element.animate()
调用
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>
CSS 动画和 Web 动画都基于将动画播放委托给浏览器的原则。这允许浏览器在可能的情况下 运行 在单独的线程或进程上播放动画,以便它 运行 流畅。尽可能避免在每一帧上从 JavaScript 更新样式。
在您的示例中,您可以简单地同时 运行 两个元素上的动画吗?至少,网络动画允许同步动画。
当其余的 Web 动画 API 发布时,从一个元素复制动画并将它们应用到另一个元素会容易得多,但现在您需要调用 animate
两次.
正如其他人指出的那样,可以观察到动画播放中的重要时刻(开始、结束、重复等),但没有任何事件 运行 在每一帧上。如果你想在每一帧上执行和操作你需要使用 requestAnimationFrame
.
如果您在 requestAnimationFrame
中将 div2
传递给 getComputedStyle
,您将获得该帧的动画样式,然后您可以将其应用于 div1
。 (也就是说,读取 div2.style.left
只会为您提供通过 style
属性指定的样式,但 getComputedStyle(div2).left
将为您提供动画样式,包括 CSS 动画和 Web 动画的样式更改).但是,同样,这会导致性能不佳,并且两个动画不一定会同步,因为 CSS 动画或 Web 动画可能 运行 在不同的线程或进程上。
如何检测 CSS3 动画或网络动画 (Element.animate
) 所做的更改??
(抱歉我的英语不好!这是我在 Whosebug 中的第一个问题)
我知道 MutationObserver,只有当我更改内联样式或使用 requestAnimationFrame
时它才会响应(因为我使用它更改了内联样式)。但是,如果我使用 CSS3 动画或 Web 动画,MutationObserver 不会响应,因为它们不会更改内联样式。
看到这个...这里有两个 div...div1,div2。当div2 的位置改变时,div1 的位置也会改变。但只有当我像我之前所说的那样使用 requestAnimationFrame 时才会发生这种情况。
我的问题是如何为 css3 动画和网络动画 (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>
对于 css 动画,您有 animationstart 和 animationend 事件可以帮助您实现您想要实现的目标。但是,没有 animationchange 或 animationupdate 事件,据我所知,这是设计使然。如果动画期间没有事件发生,则可以实现完全硬件加速,插值计算直接在 GPU 中完成。因此,请注意,虽然您可以通过 animationstart、animationend 和 requestAnimationFrame 模拟 animationchange 事件的作用,但这可能会影响性能。
你把事情复杂化了。但是要监听动画变化,您可以监听这些事件而不是变异观察器。
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
也请使用翻译而不是动画左侧 属性。
您可以使用 requestAnimationFrame
和 window.getComputedStyle()
在动画过程中获取当前动画样式,请注意,包含 fill:"forward"
在 Element.animate()
调用
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>
CSS 动画和 Web 动画都基于将动画播放委托给浏览器的原则。这允许浏览器在可能的情况下 运行 在单独的线程或进程上播放动画,以便它 运行 流畅。尽可能避免在每一帧上从 JavaScript 更新样式。
在您的示例中,您可以简单地同时 运行 两个元素上的动画吗?至少,网络动画允许同步动画。
当其余的 Web 动画 API 发布时,从一个元素复制动画并将它们应用到另一个元素会容易得多,但现在您需要调用 animate
两次.
正如其他人指出的那样,可以观察到动画播放中的重要时刻(开始、结束、重复等),但没有任何事件 运行 在每一帧上。如果你想在每一帧上执行和操作你需要使用 requestAnimationFrame
.
如果您在 requestAnimationFrame
中将 div2
传递给 getComputedStyle
,您将获得该帧的动画样式,然后您可以将其应用于 div1
。 (也就是说,读取 div2.style.left
只会为您提供通过 style
属性指定的样式,但 getComputedStyle(div2).left
将为您提供动画样式,包括 CSS 动画和 Web 动画的样式更改).但是,同样,这会导致性能不佳,并且两个动画不一定会同步,因为 CSS 动画或 Web 动画可能 运行 在不同的线程或进程上。