我在理解requestAnimationFrame API时遇到了一些麻烦。我认为这会让浏览器等待回调完成,直到浏览器触发重绘(或重排?)。那是对的吗?如果你在回调中调用requestAnimationFrame,浏览器将重新绘制并执行新的RAF的回调,然后重新重新绘制?如果是这种情况,我怎么能对这个API进行两次顺序调用更多的是异步/ promisified,而不是像下面的例子那样嵌套它们?
在这里,我使用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的先入为主的观念是否正确?以上代码示例如何能够没有回调而不是嵌套?
我不确定自己对requestAnimationFrame
的解释,但简单地说,它只是一个setTimeout(fn, the_time_until_painting_frame)
。
简单地说,它将fn
放在一个回调列表中,这些回调将在下一个绘制事件循环发生时全部执行。这个绘制事件循环是一个特殊的事件循环,浏览器将调用自己的绘制操作(CSS动画,WebAnimations等。他们将第n次标记一个事件循环作为这样的绘画框架。这通常与屏幕同步刷新率。
因此,我们的rAF回调将在此事件循环中执行,就在浏览器执行其绘制操作之前。
现在,你偶然发现的是浏览器如何计算CSS转换:它们采用元素的当前计算值。 但是这些计算值不会同步更新。浏览器通常会等待这个绘制框架以执行重新计算,因为要计算一个元素,您需要重新计算所有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>