由 JavaScript 控制的 CSS3 单向转换在按顺序添加/删除类时不起作用

CSS3 one-way transition controlled by JavaScript doesn't work when add/remove class sequentially

本文关键字:添加 顺序 删除 不起作用 控制 JavaScript CSS3 转换      更新时间:2023-09-26

我想单向地进行CSS3转换。例如,我想通过立即设置background-color: yellow;来突出显示某些元素,并通过单向过渡将其设置回background-color: white;

我尝试使用 JavaScript 来实现这一点,如下所示:

const highlightBtn = document.getElementById("highlightBtn");
const highlightToggleBtn = document.getElementById("highlightToggleBtn");
const highlightTimeoutBtn = document.getElementById("highlightTimeoutBtn");
const bodyClassList = document.getElementsByTagName("body")[0].classList;
highlightBtn.addEventListener("click", () => {
	bodyClassList.add("highlight");
  bodyClassList.remove("highlight");
  /* 
  This doesn't work, either.
  bodyClassList.toggle("highlight");
  bodyClassList.toggle("highlight");
  */
});
highlightToggleBtn.addEventListener("click", () => {
	bodyClassList.toggle("highlight");
});
highlightTimeoutBtn.addEventListener("click", () => {
  bodyClassList.add("highlight");
  setTimeout(() => {bodyClassList.remove("highlight");});
  /*
  This works, too.
  bodyClassList.toggle("highlight");
  setTimeout(() => {bodyClassList.toggle("highlight");});
  */
});
body {
	transition: background-color 1s ease;
	background-color: white;
}
body.highlight {
	transition: background-color 0s ease;
	background-color: yellow;
}
<button id="highlightBtn">
Highlight
</button>
<button id="highlightToggleBtn">
Highlight Toggle
</button>
<button id="highlightTimeoutBtn">
Highlight Timeout
</button>

问题是,如果我一次切换一次类,过渡效果很好。

// This works fine.
highlightToggleBtn.addEventListener("click", () => {
    bodyClassList.toggle("highlight");
});

但是,对于原始目标,我想突出显示该元素,所以我将添加/删除到同一元素只是想看到单向过渡,它失败了。

highlightBtn.addEventListener("click", () => {
    bodyClassList.add("highlight");
    bodyClassList.remove("highlight");
    /* 
    This doesn't work, either.
    bodyClassList.toggle("highlight");
    bodyClassList.toggle("highlight");
    */
});

但是,如果我使用延迟为 0 毫秒的setTimeout,则结果是理想的。

highlightTimeoutBtn.addEventListener("click", () => {
    bodyClassList.add("highlight");
    setTimeout(() => {bodyClassList.remove("highlight");});
    /*
    This works, too.
    bodyClassList.toggle("highlight");
    setTimeout(() => {bodyClassList.toggle("highlight");});
    */
});

为什么第二种方法不起作用?把removeClass放进去setTimeout是最好的解决方案吗?我还尝试在我的身体过渡 CSS 中延迟,例如:transition: background-color 1s ease 1ms; ,但它也不起作用。

您需要在

更改类后重排/重绘,否则浏览器将优化并直接跳到最终状态(基本上,浏览器不会更新 UI,直到所有函数都完成运行)。您可以使用 setTimeout ,但如果您觉得它太臃肿(并且 setTimeout 实际上并不总是可靠的),您可以通过访问元素的 .offsetHeight 属性来触发/强制回流:

element.classList.add('highlight')
element.offsetHeight
element.classList.remove('highlight')

我建议您阅读本文,因为它将帮助您了解更多并避免将来出现陷阱:http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/

还有其他强制回流的方法:https://gist.github.com/paulirish/5d52fb081b3570c81e3a