В прямом javascript (т.е. без расширений, таких как jQuery и т. Д.), Есть ли способ определить индекс дочернего узла внутри его родительского узла без повторения и сравнения всех дочерних узлов?
Например,
var child = document.getElementById('my_element');
var parent = child.parentNode;
var childNodes = parent.childNodes;
var count = childNodes.length;
var child_index;
for (var i = 0; i < count; ++i) {
if (child === childNodes[i]) {
child_index = i;
break;
}
}
Есть ли лучший способ определить индекс ребенка?
javascript
dom
Все работники необходимы
источник
источник
parent.childNodes
, а неparent.children
?. В последнем перечислены только узлыElements
, исключая отдельныеText
узлы ... Некоторые из ответов здесь, например, usingpreviousSibling
, основаны на использовании всех дочерних узлов, тогда как другие беспокоятся только о дочерних узлах, которые являютсяElement
... (!).childNodes
определенно следует использовать вместо.children
. Как вы указали, два первых опубликованных ответа дадут разные результаты.Ответы:
вы можете использовать это
previousSibling
свойство для повторного перебора братьев и сестер, пока не вернетесь,null
и подсчитайте, сколько братьев и сестер вы встретили:Обратите внимание, что в таких языках, как Java, есть
getPreviousSibling()
функция, однако в JS она стала свойством -previousSibling
.источник
for (var i=0; (node=node.previousSibling); i++);
i
будет доступен..previousSibling
и.previousElementSibling
. Первый попадает в текстовые узлы, второй - нет.Я стал любить использовать
indexOf
для этого. ПосколькуindexOf
он включенArray.prototype
иparent.children
естьNodeList
, вы должны использоватьcall();
Это некрасиво, но это один лайнер и использует функции, с которыми любой разработчик javascript должен быть знаком в любом случае.источник
[]
создает экземпляр массива каждый раз, когда вы запускаете этот код, что менее эффективно для памяти и GC по сравнению с использованиемArray.prototype
.[]
очищается память как значение мусора?[].indexOf
движка необходимо создать экземпляр массива только для доступа кindexOf
реализации на прототипе. Сам экземпляр не используется (он выполняет сборку мусора, это не утечка, это просто напрасная трата циклов).Array.prototype.indexOf
обращается к этой реализации напрямую, не выделяя анонимный экземпляр. Разница будет незначительной практически при любых обстоятельствах, поэтому, откровенно говоря, о ней не стоит беспокоиться.ES6:
Пояснение:
element.parentNode.children
→ Возвращает братьевelement
, включая этот элемент.Array.from
→ Приводит конструкторchildren
кArray
объектуindexOf
→ Вы можете подать заявку,indexOf
потому что теперь у вас естьArray
объект.источник
Array.from
работать в Internet Explorercreates a new Array instance from an array-like or iterable object.
Создание нового экземпляра массива только для поиска индекса может быть неэффективным с точки зрения памяти или GC, в зависимости от того, насколько часто выполняется операция, и в этом случае итерация, как описано в принятом ответе, будет больше идеально.ES-короткие
Оператор спреда - это ярлык для этого
источник
e.parentElement.childNodes
иe.parentNode.children
?childNodes
включает также текстовые узлыType 'NodeListOf<ChildNode>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
Добавление (с префиксом для безопасности) element.getParentIndex ():
источник
if (!Element.prototype.getParentIndex) Element.prototype.getParentIndex = function(){ /* code here */ }
? В любом случае, если это когда-нибудь будет реализовано в стандарте в будущем, то, скорее всего, оно будет реализовано как геттерelement.parentIndex
. Итак, я бы сказал, что лучший подход был быif(!Element.prototype.getParentIndex) Element.prototype.getParentIndex=Element.prototype.parentIndex?function() {return this.parentIndex}:function() {return Array.prototype.indexOf.call(this.parentNode.children, this)}
getParentIndex()
может иметь другую подпись, чем ваша реализация.𝗣𝗿𝗼𝗼𝗳 𝗢𝗳 𝗔 𝗟𝗲𝘀𝘀 𝗘𝗳𝗳𝗶𝗰𝗶𝗲𝗻𝘁 𝗕𝗶𝗻𝗮𝗿𝘆 𝗦𝗲𝗮𝗿𝗰𝗵
Я предполагаю, что с учетом элемента, в котором все его дочерние элементы упорядочены в документе последовательно, самым быстрым способом должен быть двоичный поиск, сравнивая позиции элементов в документе. Однако, как указано в заключении, гипотеза отвергается. Чем больше у вас элементов, тем выше потенциал для повышения производительности. Например, если у вас 256 элементов, то (оптимально) вам нужно будет проверить только 16 из них! Для 65536 всего 256! Производительность выросла до 2! Смотрите больше цифр / статистики. Посетите Википедию
Затем вы можете использовать его, получая свойство parentIndex любого элемента. Например, посмотрите следующую демонстрацию.
Ограничения
Двоичный VS линейный поиск на 200000 элементов (может привести к сбою некоторых мобильных браузеров, ОСТОРОЖНО!):
Бинарный поиск
Показать фрагмент кода
Обратный (`lastIndexOf`) линейный поиск
Показать фрагмент кода
Вперед (`indexOf`) Линейный поиск
Показать фрагмент кода
PreviousElementSibling Counter Search
Подсчитывает количество PreviousElementSiblings для получения parentIndex.
Показать фрагмент кода
Нет поиска
Для сравнения, каким был бы результат теста, если бы браузер оптимизировал поиск.
Показать фрагмент кода
Сотрясение
Однако после просмотра результатов в Chrome результаты оказались противоположными ожидаемым. Более тупой прямой линейный поиск оказался на удивление на 187 мс, что на 3850% быстрее, чем двоичный поиск. По- видимому, хром какой - то магическим перехитрить
console.assert
и оптимизирована ее, или (более оптимистично) Хром внутренне использует числовую систему индексирования для DOM, и эта внутренняя система индексации экспонирует через оптимизацию применительно кArray.prototype.indexOf
при использовании наHTMLCollection
объекте.источник
Используйте алгоритм двоичного поиска, чтобы улучшить производительность, когда узел имеет большое количество братьев и сестер.
источник
У меня была проблема с текстовыми узлами, и он показывал неправильный индекс. Вот версия, чтобы исправить это.
источник
бывший
источник
Element.prototype
? Функции выглядят полезными, но я не знаю, что они делают (даже если названия очевидны).el.group.value()
??. Мой первый комментарий предназначен для улучшения качества вашего ответа.Не могли бы вы сделать что-нибудь вроде этого:
https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement
источник
источник