Лучший способ получить дочерние узлы
Мне было интересно, JavaScript предлагает множество методов для получения первого дочернего элемента из любого элемента, но который является лучшим? В лучшем случае я имею в виду: большинство совместимых с кросс-браузером, быстрей, наиболее всеобъемлющих и предсказуемых, когда дело касается поведения. Список методов/свойств, которые я использую в качестве псевдонимов:
var elem = document.getElementById('container');
var child = elem.children[0];
var child = elem.firstElementChild; // == children[0]
Это работает для обоих случаев:
var child = elem.childNodes[0]; // or childNodes[1], see below
В случае форм или <div>
итерации. Если бы я мог столкнуться с текстовыми элементами:
var child = elem.childNodes; // treat as NodeList
var child = elem.firstChild;
Насколько я могу это сделать, firstChild
использует NodeList из childNodes
, а firstElementChild
использует children
. Im основывая это предположение на ссылке MDN:
childNode
является ссылкой на первый дочерний элемент элемента node или null
, если его нет.
Я предполагаю, что с точки зрения скорости разница, если она есть, будет почти ничего, поскольку firstElementChild
является фактически ссылкой на children[0]
, и объект children
уже в любом случае уже находится в памяти.
Что меня бросает, это объект childNodes
. Ive использовал его, чтобы взглянуть на форму в элементе таблицы. Пока children
перечисляет все элементы формы, childNodes
также, похоже, содержит пробелы из кода HTML:
console.log(elem.childNodes[0]);
console.log(elem.firstChild);
Оба log <TextNode textContent="\n ">
console.log(elem.childNodes[1]);
console.log(elem.children[0]);
console.log(elem.firstElementChild);
Все журналы <input type="text"
... >
. Как так? Id понимает, что один объект позволит мне работать с "сырым" HTML-кодом, а другой - с DOM, но элемент childNodes
, похоже, работает на обоих уровнях.
Чтобы вернуться к моему первоначальному вопросу, я бы предположил, что если я хочу наиболее полный объект, childNodes
- это путь, но из-за его полноты он может быть не самым предсказуемым с точки зрения его возвращая элемент, который я хочу/ожидаю в любой момент. Кросс-браузерная поддержка также может оказаться проблемой в этом случае, хотя я могу ошибаться.
Может ли кто-нибудь прояснить различие между объектами? Если есть разница в скорости, как бы ни была незначительна, Id тоже хотел бы знать. Если я вижу, что все это неправильно, не стесняйтесь обучать меня.
PS: Пожалуйста, мне нравится JavaScript, так что да, я хочу иметь дело с такими вещами. Ответы, подобные "jQuery" с этим для вас, не являются тем, что я ищу, следовательно, jquery.
Ответы
Ответ 1
Похоже, вы переусердствовали. Вы заметили разницу между childNodes
и children
, которая заключается в том, что childNodes
содержит все узлы, включая текстовые узлы, целиком состоящие из пробелов, а children
- это набор только дочерних узлов, которые являются элементами. Это действительно все, что есть.
Нет ничего непредсказуемого в любой коллекции, хотя есть несколько проблем, о которых нужно знать:
- IE <= 8 не содержит текстовые узлы только пробела в
childNodes
, в то время как другие браузеры
- IE <= 8 включает узлы комментариев в пределах
children
, тогда как другие браузеры имеют только элементы
children
, firstElementChild
и друзья - это просто удобства, представляющие отфильтрованный вид DOM, ограниченный только элементами.
Ответ 2
firstElementChild может быть недоступен в IE < 9 (только firstChild)
в IE < 9 firstChild является первым элементом, поскольку MS DOM (IE < 9) не хранит пустые текстовые узлы. Но если вы сделаете это в других браузерах, они вернут пустые текстовые узлы...
мое решение
child=(elem.firstElementChild||elem.firstChild)
это даст первому child даже в IE < 9
Ответ 3
Способ кросс-браузера - использовать childNodes
для получения NodeList
, затем создать массив всех узлов с nodeType
ELEMENT_NODE.
/**
* Return direct children elements.
*
* @param {HTMLElement}
* @return {Array}
*/
function elementChildren (element) {
var childNodes = element.childNodes,
children = [],
i = childNodes.length;
while (i--) {
if (childNodes[i].nodeType == 1) {
children.unshift(childNodes[i]);
}
}
return children;
}
http://jsfiddle.net/s4kxnahu/
Это особенно удобно, если вы используете служебную библиотеку, такую как lodash:
/**
* Return direct children elements.
*
* @param {HTMLElement}
* @return {Array}
*/
function elementChildren (element) {
return _.where(element.childNodes, {nodeType: 1});
}
Будущее:
Вы можете использовать querySelectorAll
в сочетании с :scope
псевдо-класса (соответствует элементу, который является точкой отсчета селектора)
parentElement.querySelectorAll(':scope > *');
На момент написания этого :scope
поддерживается в Chrome, Firefox и Safari.
Ответ 4
Эй, ребята, не пускайте пустоту в вас. просто проверьте это в браузере консоли.
используйте собственный javascript. Вот и пример с двумя наборами "ul" с тем же классом. Вам не нужно, чтобы ваш список "ul" был в одной строке, чтобы избежать пробела, просто используйте счетчик массива, чтобы перепрыгнуть через пробел.
Как обойти пустое пространство с помощью querySelector()
, затем childNodes[]
js fiddle link: https://jsfiddle.net/aparadise/56njekdo/
var y = document.querySelector('.list');
var myNode = y.childNodes[11].style.backgroundColor='red';
<ul class="list">
<li>8</li>
<li>9</li>
<li>100</li>
</ul>
<ul class="list">
<li>ABC</li>
<li>DEF</li>
<li>XYZ</li>
</ul>
Ответ 5
Чтобы добавить к другим ответам, здесь все еще есть примечательные различия, особенно при работе с элементами <svg>
.
Я использовал как .childNodes
, так и .children
и предпочел работать с HTMLCollection
, доставленным геттером .children
.
Сегодня, однако, я столкнулся с проблемами с ошибкой IE/Edge при использовании .children
на <svg>
.
Хотя .children
поддерживается в IE на основных элементах HTML, он не поддерживается в документах/фрагментах документа или элементах SVG.
Для меня я смог просто захватить необходимые элементы с помощью .childNodes[n]
, потому что у меня нет лишних текстовых узлов, о которых нужно беспокоиться. Вы можете сделать то же самое, но, как упоминалось выше, не забывайте, что вы можете столкнуться с неожиданными элементами.
Надеюсь, что это поможет кому-то почесать голову, пытаясь понять, почему .children
работает в другом месте в js на современном IE и терпит неудачу в документах или элементах SVG.