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

时间:2017-10-22 04:24:45

标签: javascript animation css-animations mutation-observers web-animations

如何检测css3动画或网络动画(Element.animate)所做的更改?

(抱歉我的英文不好!这是我在Stackoverflow中的第一个问题)

我知道MutationObserver,只有在我改变内联样式或者使用requestAnimationFrame时它才会响应(因为我使用它来改变内联样式)。但是如果我使用css3动画或Web动画,MutationObserver没有响应,因为它们没有改变内联样式。

看到这个......这里有两个div ... div1,div2。当div2的位置发生变化时,div1的位置会发生变化。但只有在我之前使用requestAnimationFrame时才会发生这种情况。

我的问题是如何为css3动画和网络动画(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";
}

/***** Animation with web animations *****/

function webAnimation() {
  div2.animate({
    left: [0, "500px"]
  }, {
    duration: 1500,
    easing: "linear"
  });
}

/*****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`;

  //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";
}
&#13;
@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;
}
&#13;
<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>
&#13;
&#13;
&#13;

4 个答案:

答案 0 :(得分:0)

对于css动画,你有animationstart和animationend事件可以帮助你实现你想要实现的目标。但是,没有 animationchange animationupdate 事件,据我所知,这是设计方式。在动画发生期间没有事件,可以实现全硬件加速,直接在GPU中完成插值计算。所以,请注意,虽然您可以通过animationstart,animationend和requestAnimationFrame来模仿animationchange事件的作用,但这可能会导致性能下降。

答案 1 :(得分:0)

你过度复杂化了。但是为了监听动画变化,你可以听取这些事件而不是变异观察者。

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

也请使用翻译而不是动画左侧属性。

答案 2 :(得分:0)

CSS动画和Web动画都基于您将动画播放委派给浏览器的原则。这允许浏览器在可能的情况下在单独的线程或进程上运行动画,以便它顺利运行。在可能的情况下,最好避免在每个帧上从JavaScript更新样式。

在您的示例中,您是否可以同时在两个元素上运行动画?至少,Web动画允许同步动画。

当发布Web动画API的其余部分时,从一个元素复制动画并将其应用到另一个元素会更容易,但现在需要两次调用animate

正如其他人所指出的那样,可以观察到动画播放中的重要时刻(当它们开始,结束,重复等)时,但是没有在每个帧上运行的事件。如果您想对每个帧执行操作,则需要使用requestAnimationFrame

如果您将div2传递给getComputedStyle中的requestAnimationFrame,您将获得该框架的动画样式,然后您可以将其应用于div1。 (也就是说,阅读div2.style.left只会为您提供通过style属性指定的样式,但getComputedStyle(div2).left将为您提供动画样式,包括CSS动画和Web动画的样式更改)。但是,再次,这将导致性能不佳,并且两个动画不一定会同步,因为CSS动画或Web动画可能在不同的线程或进程上运行。

答案 3 :(得分:-1)

您可以使用requestAnimationFramewindow.getComputedStyle()来获取动画期间的当前动画样式,注意fill:"forward" Element.animate()来电

&#13;
&#13;
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";
}
&#13;
@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;
}
&#13;
<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>
&#13;
&#13;
&#13;