JS - техника FLIP и requestAnimationFrame, рефакторинг не должен быть вложенным - PullRequest
0 голосов
/ 13 марта 2019

У меня возникли проблемы с пониманием API requestAnimationFrame. Я думаю, что это заставляет браузер ждать завершения обратного вызова, пока браузер не вызовет перерисовку (или перекомпоновку?). Это верно? Если вы вызовите 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? И как приведенный выше пример кода может быть лишен обратных вызовов, а не вложен?

1 Ответ

1 голос
/ 13 марта 2019

Я не уверен, что получу ваше собственное объяснение requestAnimationFrame, но, проще говоря, это просто setTimeout(fn, the_time_until_painting_frame).

Проще говоря, он помещает fn в список обратных вызовов, которые все будут выполнены, когда произойдет следующий цикл событий рисования. Этот цикл событий рисования представляет собой специальный цикл событий, в котором браузеры будут вызывать свои собственные операции рисования (CSS-анимации, WebAnimations и т. Д.) Они будут отмечать один цикл событий каждый n-й раз, чтобы быть таким фреймом рисования. обычно синхронизируется с частотой обновления экрана.

Таким образом, наши обратные вызовы rAF будут выполняться в этом цикле событий непосредственно перед тем, как браузер выполнит свои операции рисования.


Теперь вы наткнулись на то, как браузер вычисляет переходы CSS: они принимают текущие вычисленные значения вашего элемента.
Но эти вычисленные значения не обновляются синхронно. Браузеры обычно ждут эту рамку рисования , чтобы выполнить recalc , потому что для вычисления одного элемента вам необходимо пересчитать все дерево CSSOM.

К счастью для вас, есть некоторые методы DOM, которые синхронно инициируют такое перекомпонование, потому что им нужны обновленные значения box, например, 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>
...