Какой цели служит void element.offsetWidth? - PullRequest
0 голосов
/ 14 марта 2020

void element.offsetWidth; - это любопытная строка кода, которая, похоже, ничего не делает, но требуется для работы CSS анимации. Что делает эта строка и зачем она нужна?

Если вся строка закомментирована, анимация происходит один раз, но не повторяется. (Это все еще работает, если void удален.)

Полный код / демо здесь; Я попытался скопировать соответствующие выдержки ниже:

script. js:

beatIndicator = document.getElementById("beatIndicator"),

...

// Happens every time a beat starts:
beatIndicator.classList.remove("anim");
void beatIndicator.offsetWidth;         // Why is this line needed?
beatIndicator.classList.add("anim");

example-advanced. html

<span style="display: none;" id="beatIndicator" class="pulse"></span>


<style>
.pulse {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: #f44336;
    z-index: 3;
    left: -18px;
    display: inline-block;
    vertical-align: middle;
    margin-left: 10px;
  }

  @keyframes pulse-anim {
      from {
        box-shadow: rgba(244, 67, 54, 1) 0px 0px 0px 0px;
      }
      to {
        box-shadow: rgba(244, 67, 54, 0) 0px 0px 0px 14px;
      }
  }
  .pulse.anim {
    animation: pulse-anim;
  }
  </style>

1 Ответ

1 голос
/ 14 марта 2020

Когда вы вносите изменения в dom, например classList.remove('anim'), это может привести к каскаду изменений на странице. Рендеринг этих изменений может быть дорогостоящим, и, поскольку довольно часто вы меняете несколько вещей подряд, браузеры пытаются группировать накопленные изменения и выполнять вычисления только в конце того, что вы делаете.

Так что, если этой странной строки не было, вот что произойдет:

  • Вы удалите класс. Браузер замечает это, но пока не перерисовывает экран
  • Вы добавляете класс. Браузер отмечает это, но пока не перерисовывает экран
  • Ваша функция завершается, и браузер решает выполнить необходимые вычисления, чтобы страница соответствовала тому, что вы просили ... но ничего не изменилось ! Вы вернули страницу в то же состояние, в котором находились до запуска обработчика кликов. Поскольку ничего не изменилось, дисплей остается прежним; анимация не запускается.

То, что делает эта дополнительная строка кода, просит браузер предоставить вам информацию о домене. Но чтобы узнать, что такое offsetWidth, браузер должен отказаться от плана пакетирования изменений и выполнить переформатирование страницы прямо сейчас. В текущем состоянии нет класса run-animation, что является изменением, поэтому анимация сбрасывается. А позже, когда функция завершает свою работу, она снова выполняет вычисления и видит, что вы сделали еще одно изменение по сравнению с тем, когда оно предоставило вам offsetWidth, поэтому оно также применяет это.

Короче говоря: вы ' вынуждаете браузер выполнять дополнительную работу, и так уж бывает, что в этом случае это желательно. В большинстве случаев принуждать браузер выполнять дополнительную работу - это плохо. Большую часть времени вы хотите избегать запросов к dom таким образом, поскольку это может снизить производительность.

Другой способ заставить это работать - удалить класс сейчас, а затем добавить класс на короткое время. позже, как в:

element.addEventListener("click", function(e){
  element.classList.remove("anim");
  setTimeout(() => element.classList.add("anim"), 0);
}, false);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...