我在理解requestAnimationFrame API时遇到了一些麻烦。我认为这使浏览器等待回调完成,直到浏览器触发重画(或重排?)。那是对的吗?如果在回调中调用requestAnimationFrame,浏览器将重新绘制并执行新RAF的回调,然后再次重新绘制?如果是这种情况,如何使该API的两个顺序调用更具异步性/承诺性,而不是像下面的示例一样嵌套它们?
在这里,我使用了FLIP技术将文档片段插入DOM并为DOM元素的高度设置动画,这似乎很好用。我不喜欢代码的回调性质/嵌套。我很难理解如何使它更加异步。可以使用承诺并使其成为可能吗?
window.requestAnimationFrame(() => {
this.appendChild(frag);
this.style.height = `${rows * rowHeight}px`;
const { top: after } = this.getBoundingClientRect();
this.style.setProps({
"transform" : `translateY(${before - after}px)`,
"transition" : "transform 0s"
});
window.requestAnimationFrame(() => {
this.style.setProps({
"transform" : "",
"transition" : "transform .5s ease-out"
});
});
});
那么,我对RAF的先入为主的观念正确吗?上面的代码示例如何不包含回调而不能嵌套呢?
答案 0 :(得分:1)
我不确定自己对requestAnimationFrame
的解释,但简单来说,它只是setTimeout(fn, the_time_until_painting_frame)
。
为了简单起见,它将fn
放在回调列表中,这些回调将在下一个绘画事件循环发生时全部执行。此 painting事件循环是一个特殊的事件循环,浏览器将调用自己的绘画操作(CSS动画,WebAnimations等)。它们每n次将一个事件循环标记为一个绘画框架。通常,这与屏幕刷新率保持同步。
因此,在浏览器执行其绘画操作之前,我们的rAF回调将在此事件循环中执行。
现在,您偶然发现的是浏览器如何计算CSS过渡:它们采用元素的当前计算值。
但是这些计算值不会同步更新。浏览器通常会等待这个非常 painting frame 来执行 recalc ,因为要计算一个元素,您需要重新计算所有CSSOM树。
幸运的是,有些DOM方法将同步触发这种重排,因为它们确实需要更新的框值,例如Element.offsetTop
getter。
因此,在设置完初始样式(包括过渡样式)后,只需调用其中一种方法,便可以同步触发过渡:
_this.style.height = "50px";
_this.style.setProperty("transform", "translateY(140px)");
_this.style.setProperty("transition", "transform 0s");
_this.offsetTop; // trigger reflow
_this.style.setProperty("transform", "");
_this.style.setProperty("transition", "transform .5s ease-out");
#_this {
background: red;
width: 50px;
}
<div id="_this"></div>