zaza41rus
@zaza41rus

Как добавить общую обёртку дочерним узлам?

Как нормально обернуть в див элемент на js?
В примере оборачивается не полностью, а нужно полностью (см 3).

<ul>
  <li class="www">1</li>
  <li class="www">2</li>
  <li class="www">
    3
  <div>333</div>
  </li>
  <li class="www">4</li>
  <li class="wwwq">4</li>
</ul>

const items = document.querySelectorAll('li.www');
for (let item of items) {
  const wrapper = document.createElement('div');
  wrapper.className = 'red';
  for (let itemContent of item.childNodes) {
    wrapper.appendChild(itemContent);
  }
  item.appendChild(wrapper);
}
  • Вопрос задан
  • 132 просмотра
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
оборачивается не полностью

Почему так: childNodes представляет собой динамическую коллекцию, т.е., при добавлении или удалении узлов она обновляется без каких-либо действий с вашей стороны. Поэтому, когда вы добавляете в wrapper нулевой узел, он тут же пропадает из item.childNodes, а у оставшихся узлов позиция уменьшается на единицу - тот, что был первым, становится нулевым, второй первым и так далее. Так что когда for...of переходит к следующему узлу, им оказывается не тот, что изначально имел индекс 1, а расположенный за ним. Бывший первый, а теперь нулевой, оказывается пропущен. Аналогичным образом будут пропущены и все последующие узлы, изначально имевшие нечётные индексы.

Что тут можно сделать:

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

while (item.childNodes.length) {
  wrapper.appendChild(item.childNodes[0]);
}

Два - перебирать childNodes от конца к началу:

for (let i = item.childNodes.length; i--;) {
  wrapper.prepend(item.childNodes[i]);
}

Три - перебирать не childNodes, а массив:

for (const n of [...item.childNodes]) {
  wrapper.append(n);
}

А вообще, нет необходимости работать с каждым узлом индивидуально, метод append может принимать несколько параметров, так что переносим сразу всё:

document.querySelectorAll('.www').forEach(n => {
  const wrapper = document.createElement('div');
  wrapper.classList.add('red');
  wrapper.append(...n.childNodes);
  n.append(wrapper);
});

Или, можно и вовсе узлы не трогать, если перезаписывать разметку:

for (const n of document.getElementsByClassName('www')) {
  n.innerHTML = `<div class="red">${n.innerHTML}</div>`;
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы