JS DOM манипулирование - PullRequest
       3

JS DOM манипулирование

0 голосов
/ 14 ноября 2018

У меня возникла интересная ошибка, когда elt не определено для некоторых вызовов switchToReady.Кажется, что функция внутри setTimeout дважды проходит один и тот же узел DOM.

function switchToReady(elt) {
    elt.setAttribute('transform', 'translate(17, 0)');
    elt.classList.remove('compiling');
}

const compilingElts = document.getElementsByClassName('compiling');
for (let i = 0; i < compilingElts.length; i++) {
    const randTime = Math.round(Math.random() * (2000 - 500)) + 500;
    setTimeout(() => {
        switchToReady(compilingElts[i]);
    }, randTime);
}

Ответы [ 3 ]

0 голосов
/ 14 ноября 2018

getElementsByClassName возвращает живой список, который, как вы заметили, означает, что если вы удалите класс из элемента, список изменится (его размер).

Вместо этого вы можете использовать document.querySelectorAll('.compiling'), который возвращает список, который не является живым.

0 голосов
/ 14 ноября 2018

getElementsByClassName возвращает живую коллекцию, что означает, что если класс элемента в коллекции изменяется , пока вы выполняете итерацию по нему , или если вы добавляете другой элементс этим классом для DOM, то индекс, на котором вы находитесь (например, если i равен 2), может больше не ссылаться на старый элемент там - он может ссылаться на следующий элемент в коллекции или на предыдущийпункт, или это может быть даже undefined.Поведение довольно неинтуитивно, поэтому я бы предложил вместо этого использовать querySelectorAll, который возвращает static NodeList, который не изменится, пока вы выполняете его.

const compilingElts = document.querySelectorAll('.compiling');

Другие преимущества querySelectorAll:

  • Строка селектора, принимаемая в качестве аргумента, может быть очень гибкой - она ​​не ограничивается только классами

  • В более новых браузерах вы можете вызывать forEach непосредственно на NodeList, что устраняет необходимость в ручной итерации и отслеживании признаков:

    compilingElts.forEach((elm) => {
      const randTime = Math.round(Math.random() * (2000 - 500)) + 500;
      setTimeout(() => {
          switchToReady(elm);
      }, randTime);
    });
    

Методы массива гораздо приятнее работать, чем циклы for во многих случаях.Один из способов достижения аналогичной функциональности в старых браузерах с использованием HTMLCollection, сгенерированного из getElementsByClassName, заключается в использовании Array.prototype.forEach:

Array.prototype.forEach.call(
  compilingElts,
  (elm) => {
    // do stuff with elm
  }
);

(вместо него используется комбинация [].forEach.call, которая выполнитто же самое с меньшим количеством кода, но ссылка на Array.prototype немного яснее IMO)

0 голосов
/ 14 ноября 2018

Ах, глупая ошибка. Понял, что, удаляя класс, он меняет содержимое и, следовательно, индекс объекта compilingElts, на который ссылаются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...