Неожиданное поведение childNode

Сценарий

Я хотел бы получить все дочерние узлы моего div и изменить их цвет. Код:

function myFunction() {
  var divv = document.getElementById("divv");
  var myCollection = divv.childNodes;
  var len = myCollection.length;
  var i;
  for (i = 0; i < len; i++) {
    myCollection[i].style.color = "red";
  }
}
<div id = "divv">

  <h2>JavaScript HTML DOM</h2>

  <p>Hello World!</p>
  <p>Hello Norway!</p>
  <p>Click the button to change the color of all p elements.</p>

  <button onclick = "myFunction()">Try it</button>
</div>

Ошибка: Это не работает. Кажется, что в моей коллекции есть все узлы. h2 p текстовая кнопка. Чувствую только p h2 и buton.

РЕДАКТИРОВАТЬОбъяснение Примечание. Пробелы внутри элементов считаются текстом, а текст - узлами. Комментарии также считаются узлами.

Поэтому нам нужно проверить, является ли node узлом элемента, или использовать querySelectorAll. Примеры в ответах ниже. Спасибо за вашу помощь.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
78
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать свойство children для доступа к дочерним элементам данного узла:

The ParentNode property children is a read-only property that returns a live HTMLCollection which contains all of the child elements of the node upon which it was called.

- MDN web docs

function myFunction() {
  var divv = document.getElementById("divv");
  var myCollection = divv.children;
  var len = myCollection.length;
  var i;
  for (i = 0; i < len; i++) {
    myCollection[i].style.color = "red";
  }
}
<div id = "divv">
  <h2>JavaScript HTML DOM</h2>
  <p>Hello World!</p>
  <p>Hello Norway!</p>
  <p>Click the button to change the color of all p elements.</p>
  <button onclick = "myFunction()">Try it</button>
</div>

Другой способ сделать с ES6 - распределить дочерние узлы в массив и перебрать их с помощью .forEach:

const myFunction = () => {
  
  [...document.querySelector('#divv').children].forEach(child => {
  
    child.style.color = 'red';
  
  });
  
}
<div id = "divv">
  <div class = "child">
    I am a child
  </div>
  <div>
    <div class = "grandchild">
      I am a grand child
    </div>
  </div>
  
  <button onclick = "myFunction()">Try it</button>
</div>

В качестве альтернативы вы можете использовать .forEach из класса NodeList напрямую, но предыдущий метод дает вам больше свободы для работы с методом Array, таким как .reduce, .map и т. д.

const myFunction = () => {
  
  document.querySelectorAll('#divv > *').forEach(child => {
  
    child.style.color = 'red';
  
  });
  
}
<div id = "divv">
  <div class = "child">
    I am a child
  </div>
  <div>
    <div class = "grandchild">
      I am a grand child
    </div>
  </div>
  
  <button onclick = "myFunction()">Try it</button>
</div>

ChildNode всегда возвращает и внуков?

zolty13 13.07.2018 10:13

@ zolty13, нет The Node.childNodes read-only property returns a live NodeList of child nodes of the given element where the first child node is assigned index 0., поэтому возвращает только детей, а не внуков. Но помните, что, добавляя стиль к родительскому элементу, вы также добавляете стиль детям и внукам!

Ivan 13.07.2018 10:18

Итак, почему я получаю 11 элементов из childNode. @CertainPerfomance использует: if (myCollection [i] .nodeType === 1) myCollection [i] .style.color = "red";

zolty13 13.07.2018 10:21

Да, вы получаете 11, посмотрите на myCollection, есть только дочерние узлы, а не внуки

Ivan 13.07.2018 10:24

@ zolty13, чтобы отличить text от element: прочтите это

Ivan 13.07.2018 10:24

Я ожидаю h2 p p p и бутон

zolty13 13.07.2018 10:28

Я получил объяснение: Примечание. Пробелы внутри элементов считаются текстом, а текст - узлами. Комментарии также считаются узлами. Спасибо за помощь

zolty13 13.07.2018 10:35

Текстовые узлы не имеют атрибутов style. Если вы хотите использовать childNodes, сначала убедитесь, что nodeType равен 1 (узел Element):

function myFunction() {
  var divv = document.getElementById("divv");
  var myCollection = divv.childNodes;
  var len = myCollection.length;
  var i;
  for (i = 0; i < len; i++) {
    if (myCollection[i].nodeType === 1) myCollection[i].style.color = "red";
  }
}
<div id = "divv">
  <h2>JavaScript HTML DOM</h2>
  <p>Hello World!</p>
  <p>Hello Norway!</p>
  <p>Click the button to change the color of all p elements.</p>
  <button onclick = "myFunction()">Try it</button>
</div>

Но я бы предпочел использовать здесь querySelectorAll и forEach:

function myFunction() {
  document.querySelectorAll('#divv > *')
    .forEach(child => child.style.color = "red");
}
<div id = "divv">
  <h2>JavaScript HTML DOM</h2>
  <p>Hello World!</p>
  <p>Hello Norway!</p>
  <p>Click the button to change the color of all p elements.</p>
  <button onclick = "myFunction()">Try it</button>
</div>

(или вы можете просто установить #divvstyle.color на красный)

Спасибо. Дело не только в цвете :). Это простой пример моей проблемы. Я не понимаю, почему я получаю текстовые узлы, когда мне нужен только дочерний узел. Текстовый узел - внук. var myCollection = divv.childNodes;

zolty13 13.07.2018 10:11

Потому что childNodes будет включать текстовые узлы. Новые строки также являются текстовыми узлами. Если вам не нужны текстовые узлы, у вас может быть HTML, например <h2>JavaScript HTML DOM</h2><p>Hello World!</p><p>Hello Norway!</p>, без новой строки и без пробелов между элементами <>s.

CertainPerformance 13.07.2018 10:23

Другие вопросы по теме