【问题标题】:Restart css transition重启css过渡
【发布时间】:2023-12-23 06:42:01
【问题描述】:

我正在尝试在 Javascript and without librairies or css 中重新启动 transition。我不想用SettimeoutclientHeight 之类的技巧来实现这一点。我知道这是因为回流,但我正在尝试为此找到理想的解决方案。

步骤如下:

1)Removetransition -> 设置新位置(withouttransition)

2) Add 过渡 -> 设置新位置(with 动画)

这里是 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)"

}

现在只是进行过渡和移动 10px,而不是先设置 50px 的位置。

【问题讨论】:

  • 你必须使用过渡吗?使用关键帧是不可能的吗?
  • 是的,它只使用过渡,没有 css 或 css 动画

标签: javascript html css css-transitions


【解决方案1】:

您的代码不起作用,因为浏览器不会重新计算您的第一批和第二批“更新”之间的样式。

一个技巧是通过调用其中一个函数来强制浏览器重新计算它们。例如,我将使用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
  • 我的意思是,如果你不强制重新计算,因为你没有调用任何重新计算方法,浏览器只会重新计算每批更新一次,但如果你强制它,浏览器将重新计算每批更新一次,并且每次您强制它时。有更好的方法来实现这一点,但它们需要 CSS 或 requestAnimationFrame(某种 setTimeout),所以 AFAIK,在这种情况下你能做的最好的就是我的回答。
  • 对于这种情况你有 requestAnimationFrame 的例子吗?
  • 没那么容易。为此最好使用库,例如​​fastDOMrequestAnimationFrame 只是确保每次重新计算每帧执行 1 次,而不在意您所做的更改量。简单将所有“读取”批处理在一个函数中,将所有“写入”批处理在另一个函数中,然后每帧调用一次。如果您在代码的不同部分执行 100 次读取和 50 次写入,它们都将被“打包”到一个函数中。在这种情况下,与添加setTimeout 完全相同,因为您只有一个“批次”更改。这就是为什么我说是某种 setTimeout。让我准备一把小提琴。
  • 第二个的行为几乎与添加一个 setTimeout 相同,只是它将在浏览器的“绘制”时刻被触发。对此进行了更优化。第二个具有较少的性能开销,因为它每帧只调用一次,因此如果用户启用自动点击器并每毫秒点击一千次,则只会发生一次重新计算。第一种方式(没有requestAnimationFrame )将在每次点击时重新计算,无论 FPS。
【解决方案2】:

你可以在没有任何 JS 的情况下实现它,只需要两个 CSS 选择器:一个描述静态状态,另一个在目标状态上启用 transition

.box {
  background: red;
  height: 100px;
  width: 100px;
}

.box:hover {
  transform: rotate(180deg);
  transition: transform .3s linear;
}
<div class="box"></div>

使用这种方式只会给你一个过渡方向

【讨论】:

  • 我在我的问题中说没有 CSS。我知道这可以在 css 中轻松实现,但这是一个约束
  • @zaarr78 约束是人为的,因为只要你会写 JS,你也可以做 CSS。直接在 JS 中处理转换是反模式
  • 这是一个没有css的项目。目的是写代码而不写任何CSS
【解决方案3】:

您可以在transitionEnd事件中添加一个EventListener,然后更改类:

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";
     }
  }
}

如果你不想使用这个类,你仍然可以使用这个结构来改变你的样式。

在你第一次点击你开始转换

【讨论】: