requestAnimationFrame vs settimeout 0 для анимации display:none

163
24 марта 2019, 17:30

Пытаюсь сделать анимационные переходы как во Vue.js для блока с display:none

То-есть сначала блоку добавляется display, на следующем кадре должна начаться анимация, после transitionend все классы удаляются.

Изначально планировал использовать для определения следующего кадра requestAnimationFrame, но он отказывается правильно работать. Блок плавно скрывается, но появляется резко. Так же заметил что иногда код отрабатывает как надо, блок появляется плавно.

Кто знает в чем разница между requestAnimationFrame и setTimeout 0? И есть ли смысл использовать requestAnimationFrame для подобных целей?

Пример с requestAnimationFrame (Работает не всегда корректно).

Пример рабочего кода с setTimeout

HTML

<button id=btn1>Нажми</button>
<div id="con1" style="display: none;">Контент</div>

JS

var btn = document.getElementById('btn1');
var con = document.getElementById('con1');
var show = false;
btn.addEventListener('click', function(e) {
    if (!show) {
        con.classList.add('fade-enter');
        con.classList.add('fade-enter-active');
        con.style.display = "";
        setTimeout(function() {
            con.classList.remove('fade-enter');
            con.classList.add('fade-enter-to');
            con.addEventListener('transitionend', function n(e) {
                con.classList.remove('fade-enter-active');
                con.classList.remove('fade-enter-to');
                con.removeEventListener('transitionend', n);
            });
        }, 0)
    } else {
        con.classList.add('fade-leave');
        con.classList.add('fade-leave-active');
        setTimeout(function() {
            con.classList.remove('fade-leave');
            con.classList.add('fade-leave-to');
            con.addEventListener('transitionend', function n(e) {
                con.classList.remove('fade-leave-active');
                con.classList.remove('fade-leave-to');
                con.style.display = "none"
                con.removeEventListener('transitionend', n);
            });
        }, 0)
    }
    show = !show;
});

CSS

.fade-enter, .fade-leave-to {
  opacity: 0;
}
.fade-enter-active, .fade-leave-active {
  transition: opacity 1s;
}
#con1 {
    width: 300px;
    height: 300px;
    background-color: #ddd;
}
Answer 1

Проблема была в том что requestAnimationFrame не гарантирует вызова в следующем кадре.

Paul Irish

All rAF callbacks always run in the same or next frame of work Any rAFs queued in your event handlers will be executed in the ​same frame​. Any rAFs queued in a rAF will be executed in the next frame​. (Same for any queued within IntersectionObserver or ResizeObserver callbacks.)

Для правильного поведения нужно вызвать requestAnimationFrame в requestAnimationFrame

let raf = window.requestAnimationFrame;
let nextFrame = function(fn) {
    raf(function() {
        raf(fn);
    });
};
READ ALSO
Как сделать такой Range Slider?

Как сделать такой Range Slider?

Как можно сделать такой слайдер? второй день голову ломаю, помогите плиз, мб есть готовые плагины какие-тоКовырял jqueryUI и noUiSlider но так и не победил...

153
как убрать скачек экрана вверх при клике на ссылку?

как убрать скачек экрана вверх при клике на ссылку?

Есть такой кусок кодаЭто табы, и при клике по переключателю страничка подпрыгивает, я допер почему она подпрыгивает, из-за значка #, так вот...

152
Как может выглядеть Ajax отправка формы без jQuery?

Как может выглядеть Ajax отправка формы без jQuery?

Есть типовой скрипт отправки писем на jQuery HTML:

158
Как лучше сделать блюр в Canvas ?

Как лучше сделать блюр в Canvas ?

Может кто сталкивался с таким кейсом или может есть какая то либа максимально приближенная к задаче ?

162