Почему браузер игнорирует анимацию?

160
31 октября 2018, 17:10

сейчас я разбираюсь с анимационными эффектами с помощью css и javascript и хочу реализовать алгоритм похожий на VueJs чтобы лучше понимать как это все работает и вот столкнулся с несколькими проблемами и вопросами.

  1. Почему в обработчике события для btnShow если я не буду использовать таймер на 0 секунд, то у меня просто не сработает анимация, ведь алгоритм вроде правильный сначала ставлю класс enter, чтобы задать начальные стили, потом задаю enter-active - для изменения начальных стилей, потом сразу удаляю enter, и когда сработает событие transitionend уберу обработчик события на элемент. В теории все должно работать, но на практике получается все не так, анимация во все не работает, js вообще не ставит класс enter, я конечно догадываюсь, что это такая оптимизация браузера и что типа браузер видит добавление, а потом удаление класса и вообще его не ставит, но все равно я не понимаю как это работает и почему. Почему браузер не выполняет команды подряд, почему код ведет себя так непредсказуемо, что этому способствует?

    elem.style.display = 'inline-block';
    elem.classList.add('enter');
    elem.classList.add('enter-active');
    elem.classList.remove('enter');
    
  2. Почему settimeout это исправляет?

  3. Почему опять же если я чуть меняю алгоритм и здесь уже сразу после enter добавляю enter-active, то анимация тоже не сработает, браузеру именно надо чтоб я добавил сначала enter, а потом ставил интервал и только в нем уже добавлял новый класс и удалял старый. Почему так ? Как это вообще работает, уже голова кругом если честно))

    elem.style.display = 'inline-block'; elem.classList.add('enter'); elem.classList.add('enter-active'); setTimeout(function() { elem.classList.remove('enter'); }, 0);

    Заранее большое спасибо, если объясните как это все работает в браузере и почему надо делать именно так, чтоб в дальнейшем это не было сюрпризом для меня))

var btnHide = document.querySelector('.hide'); 
var btnShow = document.querySelector('.show'); 
var elem = document.querySelector('.block'); 
btnHide.addEventListener('click', function () { 
    elem.classList.add('leave-active'); 
    function handler() { 
        elem.style.display = "none"; 
        elem.classList.remove('leave-active'); 
        elem.removeEventListener('transitionend', handler); 
    } 
    elem.addEventListener('transitionend', handler); 
}); 
 
btnShow.addEventListener('click', function () { 
    elem.style.display = 'inline-block'; 
    elem.classList.add('enter'); 
  //  elem.classList.add('enter-active'); ?? 
    setTimeout(function() { 
        elem.classList.remove('enter'); 
        elem.classList.add('enter-active'); 
    }, 0); 
    elem.addEventListener('transitionend', function() { 
        elem.classList.remove('enter-active'); 
    }); 
});
.block { 
    background: greenyellow; 
    display: inline-block; 
    margin: 15px; 
} 
 
.leave-active { 
    transition: opacity, 1s; 
    opacity: 0; 
    transform: translateX(200px); 
} 
.enter { 
    opacity: 0; 
    transform: translateX(-200px) 
} 
.enter-active { 
    transition: opacity 1s, transform 1s; 
    opacity: 1; 
}
 <div class="btns"> 
        <button class="hide">Hide</button> 
        <button class="show">Show</button> 
    </div> 
    <div class="block"> 
        <p>Lorem ipsum dolor sit amet.</p> 
        <p>Vitae nemo labore autem tempora.</p> 
        <p>Tenetur earum ab suscipit unde?</p> 
        <p>Labore eius accusantium ullam voluptatum.</p> 
        <p>Necessitatibus similique mollitia cumque incidunt.</p> 
    </div> 
    <div class="some"> 
        <p>Lorem, ipsum.</p> 
    </div>

Answer 1

https://developer.mozilla.org/ru/docs/Web/API/Element/classList
elem.classList.toggle( String [, Boolean])
Если класс у элемента отсутствует - добавляет, иначе - убирает.
Когда вторым параметром передано false - удаляет указанный класс, а если true - добавляет.

Пример раз

var btnHide = document.querySelector('#hide'); 
var btnShow = document.querySelector('#show'); 
var elem = document.querySelector('.block'); 
// -- 
btnHide.addEventListener('click', function() { 
  // это 
  // elem.classList.remove('enter'); 
  // elem.classList.add('leave'); 
  // заменятся на это 
  elem.classList.toggle("leave"); 
}); 
// -- 
btnShow.addEventListener('click', function() { 
  // это 
  // elem.classList.remove('leave'); 
  // elem.classList.add('enter'); 
  // заменятся на это 
  elem.classList.toggle("leave"); 
}); 
// --
.block { 
  background: greenyellow; 
  display: inline-block; 
  margin: 15px; 
  overflow: hidden; 
  height: 250px; 
  /*показываем медленнее*/ 
  transition: height 4s, opacity 1s, transform 1s; 
 
  /* это для наглядности - удалить 
  opacity: 1; 
  transform: translateX(0px) 
  */ 
} 
 
.leave { 
  /*прячем - быстрее*/ 
  transition: height 2s, opacity 1s, transform 1s; 
  opacity: 0; 
  height: 0; 
  transform: translateX(200px); 
} 
 
 
/* это для наглядности - удалить 
.enter { 
    opacity: 1; 
    transform: translateX(0px) 
} 
*/
<div class="btns"> 
  <button id="hide">Hide</button> 
  <button id="show">Show</button> 
</div> 
<div class="block"> 
  <p>Lorem ipsum dolor sit amet.</p> 
  <p>Vitae nemo labore autem tempora.</p> 
  <p>Tenetur earum ab suscipit unde?</p> 
  <p>Labore eius accusantium ullam voluptatum.</p> 
  <p>Necessitatibus similique mollitia cumque incidunt.</p> 
</div> 
<div class="some"> 
  <p>Lorem, ipsum.</p> 
</div>

у этого примера есть недостаток - необходимо заранее знать высоту

.block {
  height: 250px;
}

эта проблема решается с помощью JS так

Пример два

var btnHide = document.querySelector('#hide'); 
var btnShow = document.querySelector('#show'); 
var elem = document.querySelector('.block'); 
// -- 
btnHide.addEventListener('click', function() { 
  // это 
  // elem.classList.remove('enter'); 
  // elem.classList.add('leave'); 
  // заменятся на это 
  elem.classList.toggle("leave"); 
}); 
// -- 
btnShow.addEventListener('click', function() { 
  // это 
  // elem.classList.remove('leave'); 
  // elem.classList.add('enter'); 
  // заменятся на это 
  elem.classList.toggle("leave"); 
}); 
// -- 
    let elStyle = getComputedStyle(elem); 
    document.head.insertAdjacentHTML('beforeend', ` 
        <style> 
        .block { 
            background: greenyellow; 
            display: inline-block; 
            margin: 15px; 
            overflow: hidden; 
            height: ${elStyle.height}; 
            /*показываем медленнее*/ 
            transition: height 4s, opacity 1s, transform 1s; 
        } 
 
        .leave { 
            /*прячем - быстрее*/ 
            transition: height 2s, opacity 1s, transform 1s; 
            opacity: 0; 
            height: 0; 
            transform: translateX(200px); 
        } 
        </style> 
    `)
<div class="btns"> 
  <button id="hide">Hide</button> 
  <button id="show">Show</button> 
</div> 
<div class="block"> 
  <p>Lorem ipsum dolor sit amet.</p> 
  <p>Vitae nemo labore autem tempora.</p> 
  <p>Tenetur earum ab suscipit unde?</p> 
  <p>Labore eius accusantium ullam voluptatum.</p> 
  <p>Necessitatibus similique mollitia cumque incidunt.</p> 
</div> 
<div class="some"> 
  <p>Lorem, ipsum.</p> 
</div>

READ ALSO
Подскажите легкий скрипт аудиоплеера

Подскажите легкий скрипт аудиоплеера

Подскажите скрипт аудиоплеера, который можно было бы использовать с минимальными изменениями в разметке - например, задать соответствующие...

154
React.js: логика обработки модального окна

React.js: логика обработки модального окна

Не могу понять, каким образом стоит отлавливать действия пользователя в модальном окне

274
Выход из рекурсии

Выход из рекурсии

Не могу выйти из рекурсии

202
Посчитать значение всех input type=&ldquo;time&rdquo;

Посчитать значение всех input type=“time”

помогите посчитать значения всех inputПробовал преобразовать значение инпут с помощью parseInt, считает некорректно

179