JS — FLIP技术和requestAnimationFrame,重构为不嵌套

JS — FLIP technique and requestAnimationFrame, refactor to not be nested

我在理解 requestAnimationFrame 时遇到一些问题 API。我认为这会让浏览器等待回调完成,直到浏览器触发重绘(或回流?)。那是对的吗?如果在回调中调用requestAnimationFrame,浏览器会重绘并执行新RAF的回调然后再重绘?如果是这种情况,我怎样才能对这个 API 进行两次连续调用 async/promisified 而不是像下面的示例那样嵌套它们?

在这里,我使用了 FLIP 技术将文档片段插入 DOM 并为 DOM 元素的高度设置动画,它似乎工作正常。我不喜欢代码的回调nature/nesting。我很难理解如何使它更加异步。是否可以使用承诺并使其可用?

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

    });

});

那么,我对英国皇家空军的先入之见是正确的吗?上面的代码示例如何没有回调而不是嵌套?

我不确定你对requestAnimationFrame的解释,但简单地说,它只是一个setTimeout(fn, the_time_until_painting_frame)

简单地说,它将 fn 放入回调列表中,这些回调将在下一次绘制事件循环发生时全部执行。这个painting event loop是一个特殊的event loop,浏览器会调用自己的painting operations(CSS animations, WebAnimations etc.每n次就会标记一个event loop就是这样的画框,这个一般是和屏幕刷新率同步的

所以我们的 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>