Почему функция insertBefore добавляет элемент не туда, куда я хочу?

177
21 июня 2018, 22:20

Коллеги, есть такой пример (далее опишу проблему в комментариях в коде):

//Код ниже работает, но почему то не верно 
// DIV добавляется после SPAN 
//  но если раскомментировать  закомментированные строки 
// 
// то работает, но DIV добавляется только в первый элемент 
const li = document.querySelectorAll('li'), 
  //span = document.querySelector('span'),  //раскоментировать 
  span = document.querySelectorAll('span'), // закоментировать 
  bg = document.createElement('div'); 
 
li.forEach(s => { 
  s.addEventListener('click', () => { 
    let bg_passive = bg.cloneNode(); 
    bg_passive.className = 'bg-passive'; 
 
    if (s.childNodes.length <= 1) { 
      //s.insertBefore(bg_passive, span); // раскоментировать 
      s.insertBefore(bg_passive, s.span); // закоментировать 
      console.log(s.childNodes); 
 
    } 
 
  }) 
})
li { 
  width: 30px; 
  height: 100%; 
  list-style: none; 
} 
 
span { 
  border: 1px solid black; 
  display: block; 
  background: green; 
}
<menu> 
  <li><span>1</span></li> 
  <li><span>2</span></li> 
  <li><span>3</span></li> 
  <li><span>4</span></li> 
  <li><span>5</span></li> 
  <li><span>6</span></li> 
</menu>

Answer 1

Всё там правильно!

document.querySelector('span') - выбирает только 1-ый span в документе. document.querySelectorAll('span') - выбирает все span-ы в документе.

Если функции insertBefore передавать один и тот же span, то она и будет им пользоваться.

Если хотите, чтобы работало так, как вы хотите, то замените строку:

s.insertBefore(bg_passive, span);

на

s.insertBefore(bg_passive, s.firstChild);

Добавлено 2 часа спустя:

Если же строку ту всё же оставить как s.insertBefore(bg_passive, s.span);, то поскольку s.span = undefined, то согласно документации, вставляемый элемент вставляется в конец списка дочерних элементов. Именно поэтому во втором случае вам кажется, что там правильно, но на самом деле там надо передавать s.firstChild, чтобы было так, как вы хотите.

Answer 2

Да криво реализовано вообще, вот так всё работает. Без лишних велосипедов,а вообще это всё действие можно до 3-х строчек кода сжать на JQ.

//Код ниже работает, но почему то не верно 
// DIV добавляется после SPAN 
//  но если раскомментировать  закомментированные строки 
// 
// то работает, но DIV добавляется только в первый элемент 
const li = document.querySelectorAll('li'), 
  span = document.querySelector('span'),  //раскоментировать 
  bg = document.createElement('div'); 
 
li.forEach(s => { 
  s.addEventListener('click', () => { 
    let bg_passive = bg.cloneNode(); 
    bg_passive.className = 'bg-passive'; 
console.log(s.childNodes); 
    if (s.childNodes.length <= 1) { 
      s.insertBefore(bg_passive, event.target); // раскоментировать 
      console.log(s.childNodes); 
    } 
  }) 
})
li { 
  width: 30px; 
  height: 100%; 
  list-style: none; 
} 
 
span { 
  border: 1px solid black; 
  display: block; 
  background: green; 
}
<menu> 
  <li><span>1</span></li> 
  <li><span>2</span></li> 
  <li><span>3</span></li> 
  <li><span>4</span></li> 
  <li><span>5</span></li> 
  <li><span>6</span></li> 
</menu>

READ ALSO
Bootstrap 4 dropdown profile - выпадающий профиль

Bootstrap 4 dropdown profile - выпадающий профиль

Хочу сделать выпадающее окно профиляНо выпадает оно почему-то не в том месте:

250
размытие текста при использовании transform translate 3d

размытие текста при использовании transform translate 3d

Есть слайдер slick в нем элементы перемещаются с помощью transfrom translate 3d но при этом в блоках размытый текст если убрать этот трансформ текст нормальный...

235