重新启动 CSS 过渡效果。

3
我正在尝试使用JavaScript重新启动没有库或CSS的过渡。我不想使用像Settimeout或clientHeight这样的技巧来实现此目的。我知道这是由于回流,但我正在尝试找到最理想的解决方案。
以下是步骤:
1)删除过渡->设置新位置(无过渡)
2)添加过渡->设置新位置(带动画)
以下是JavaScript代码。
let element1 = document.querySelector(".box")

document.querySelector("button").onclick = () => {

  element1.style.transition = "none"
  element1.style.transform = "translateY(50px)"

  element1.style.transition = "all 0.4s";
  element1.style.transform = "translateY(10px)"

}

当前只进行了移动10像素的过渡,而没有首先设置50像素的位置。


你是否必须使用过渡效果?使用关键帧是不可行的吗? - rebecca
是的,它只使用了过渡效果,没有使用CSS或CSS动画。 - zaarr78
2个回答

4

您的代码无法工作是因为浏览器在您进行第一批和第二批更新之间不会重新计算样式。

一个技巧是通过调用一个重新计算样式的函数来强制浏览器重新计算它们。例如,我将使用getBoundingClientRect,因为浏览器需要计算样式以获取元素的大小和位置。

所以:

let element1 = document.querySelector(".box")
document.querySelector("button").onclick = () => {
  // Call the first batch of updates
  element1.style.transition = "none";
  element1.style.transform = "translateY(50px)";
  
  // Force the browser recalculate the styles
  element1.getBoundingClientRect();

  // Call the second batch of updates
  element1.style.transition = "all 0.4s";
  element1.style.transform = "translateY(10px)";
}

如果您每秒钟调用这个函数很多次,那么是的,因为重新计算不便宜(另外还取决于HTML节点数量、CSS复杂度、层数和其他一堆因素)。您想要实现的(在批处理之间重新计算)并不是一件廉价的事情。顺便说一下,我不认为用户会点击按钮100次每秒 xD。 - Jorge Fuentes González
我的意思是,如果你不强制重新计算,因为你没有调用任何重新计算的方法,浏览器只会在每批更新中重新计算一次,但如果你强制它,浏览器将在每批更新中重新计算一次,并且每次你强制它。有更好的方法来实现这一点,但它们需要CSS或requestAnimationFrame(一种类似于setTimeout的东西),所以据我所知,在这种情况下,你能做的最好的就是我回答的内容。 - Jorge Fuentes González
你有没有关于这种情况的requestAnimationFrame的示例? - zaarr78
这并不容易。更好的方法是使用一个库,比如 fastDOMrequestAnimationFrame 简单地确保每次重新计算都在一帧内完成,不管你做了多少改变。简单地将所有的“读取”操作放在一个函数中,将所有的“写入”操作放在另一个函数中,并在每帧调用它们一次。如果您在代码的不同部分进行了100次读取和50次写入,它们都将被“打包”到一个函数中。在这种情况下,与添加 setTimeout 完全相同,因为您只有一个“批处理”更改。这就是我说的类似于 setTimeout 的东西。让我准备一个 fiddle。 - Jorge Fuentes González
第二种方法几乎与添加setTimeout相同,只是它将在浏览器的“绘制”时刻触发。更为优化。第二种方法的性能开销较小,因为它每帧只调用一次,因此如果用户启用自动点击器并每毫秒点击一千次,则仅会发生一次重新计算。第一种方法(不使用requestAnimationFrame)将在每次单击时重新计算,无论FPS如何。 - Jorge Fuentes González
没有CSS,是的。但是如果您无法使用setTimeout(我不知道为什么),也许您将无法使用requestAnimationFrame。顺便说一下,你在这里都有答案 xD。 - Jorge Fuentes González

0
您可以添加一个EventListener到transitionEnd事件,然后更改类:
let element1 = document.querySelector(".box");

element1.addEventlistener("transitionend", loopTransition(),false);
element1.addEventListener("webkitTransitionEnd", loopTransition, false);
element1.addEventListener("mozTransitionEnd", loopTransition, false);
element1.addEventListener("msTransitionEnd", loopTransition, false);
element1.addEventListener("oTransitionEnd", loopTransition, false);


function loopTransition(e) {
  if (e.propertyName == "transform") {
      if (element1.className == "stateTwo") {
          element1.className = "stateOne";
      } else {
          element1.className = "stateTwo";
     }
  }
}

如果您不想使用类,仍然可以使用此结构来更改样式。
在您的第一个onclick中开始转换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接