Я хочу найти индекс данного узла DOM. Это как обратное действие
document.getElementById('id_of_element').childNodes[K]
Вместо этого я хочу извлечь значение K, учитывая, что у меня уже есть ссылка на дочерний узел и родительский узел. Как мне это сделать?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я думаю, что единственный способ сделать это - перебрать потомков родителя, пока не найдешь себя.
var K = -1;
for (var i = myNode.parent.childNodes.length; i >= 0; i--)
{
if (myNode.parent.childNodes[i] === myNode)
{
K = i;
break;
}
}
if (K == -1)
alert('Not found?!');
Ответ Роборга работает ... или вы можете попробовать ...
var k = 0;
while(elem.previousSibling){
k++;
elem = elem.previousSibling;
}
alert('I am at index: ' + k);
Немного короче, ожидает, что элемент будет в элементе, возвращает k.
for (var k=0,e=elem; e = e.previousSibling; ++k);
После комментария от Джастин Диринг я просмотрел свой ответ и добавил следующее:
Или, если вы предпочитаете «пока»:
var k=0, e=elem;
while (e = e.previousSibling) { ++k;}
Первоначальный вопрос заключался в том, как найти индекс существующего элемента DOM. В обоих моих примерах выше в этом ответе ожидается, что элем будет элементом DOM и что этот элемент все еще существует в DOM. Они потерпят неудачу, если вы дадите им нулевой объект или объект, у которого нет предыдущий. Более надежный способ будет выглядеть примерно так:
var k=-1, e=elem;
while (e) {
if ( "previousSibling" in e ) {
e = e.previousSibling;
k = k + 1;
} else {
k= -1;
break;
}
}
Если е - это ноль или если предыдущий отсутствует в одном из объектов, k равно -1.
@some, мне пришлось изменить пример, и похоже, что вам нужно переместить e = e.previousSibling в замешательство цикла for и выполнить нулевую проверку в firefox 3.5.
@Justin: "e = e.previousSibling" находится посередине ... Цикл for объявляет k = 0 и e = elem. Затем он выполняет e = e.previousSibling до тех пор, пока e === null. Для каждого успешного цикла он увеличивает k на единицу. И это работает в FF3.5.2. Пожалуйста, объясните, что вы считаете неправильным.
@Justin: Добавил еще несколько примеров.
some - Если я могу предложить, поскольку выше / ниже являются относительными спецификаторами, вы можете подумать о том, чтобы вставить «Оба приведенных выше примера (1 & 2) ожидают элем» вместо аналогичного текста в вашем ответе, поэтому, если это когда-либо актуально, кто-то знает, о каких двух предыдущих примерах (если я прав) вы говорите.
К вашему сведению, самый быстрый способ сделать это, по-видимому, - использовать цикл for. Источник: jsperf.com/fastest-way-to-get-index-of-element-in-a-nodelist
@brunoais В примере for вы используете previousElementSibling и получаете результат 24, но в while вы используете previousSibling с результатом 49. Я создал новый прецедент, где они оба используют previousElementSibling, и тогда не так уж много разница больше в моем ограниченном тестировании по крайней мере. На самом деле while был немного быстрее в FF20 на Win7.
@brunoais, а в IE10 for и while примерно на 40% медленнее, чем indexOf ... Вы получаете элементы в живом HTMLCollection. Преобразуя это в массив вместо Array.prototype.slice.call(main.children,0), который также является самым быстрым в FF20.
@ user66001 Извините, что я не заметил вашего комментария до сих пор. Собственно, в своем ответе я имел в виду свои собственные примеры, где они находятся над примечанием. Извините, если это было непонятно.
@brunoais Для справки в будущем: на машинном уровне нет почти никакой разницы между циклом for и циклом while. Если вы сравните две функции, одна из которых использует для, а другая пока, и получите значительную разницу во времени, вы, вероятно, делаете что-то не так.
@some На самом деле это неверно для любого языка сценариев, потому что перевод в машинный код отличается, и компиляция также может быть другой. «За», подобное тому, что я сделал, можно рассматривать как единый «блок», который распознается внутренними компонентами и уже имеет алгоритмы, оптимизирующие его. Пока это можно рассмотреть в 2 этапа. Создание переменной и время. Итак, в C или java, или C# и т. д. Это точно так же, но для php или javascript это совсем другое.
@some - НП. Для меня это было непонятно, учитывая, что в начале предложения говорилось об исходном вопросе. Спасибо за разъяснение :)
@some - Спасибо. Намного лучше i.m.o, но, надеюсь, это поможет другим :)
используя фреймворк, такой как прототип, вы можете использовать это:
$(el).up().childElements().indexOf($(el))
Как и в случае с оригинальным плакатом, я пытался
find the index of a given DOM node
но тот, на котором я просто использовал обработчик кликов, и только по отношению к своим братьям и сестрам. Я не смог заставить вышеуказанное работать (несомненно, из-за noobness, я попытался подставить 'this' для elem, но это не сработало).
Мое решение заключалось в использовании jquery и использовании:
var index = $(this).parent().children().index(this);
Он работает без указания типа элемента, например: 'h1', идентификатора и т. д.
Кратчайший путь, без каких-либо фреймворков, во всех версиях Safari, FireFox, Chrome и IE> = 9:
var i = Array.prototype.indexOf.call(e.childNodes, someChildEl);
Тоже был бы мой ответ :) +1!
Примечание: замените e.childNodes на e.children, чтобы найти индекс элемента в его родственном элементе элементы - в отличие от родственного элемента узлы, который включает текстовые узлы и узлы комментариев.
аналогичный пример приведен в MDN: developer.mozilla.org/en-US/docs/DOM/NodeList#Workarounds
Почему мы не можем сделать что-то вроде e.parentNode.childNodes.indexOf(e)? Обновлено: я только что это проверил. NodeList не является настоящим Array, поэтому мы должны использовать имплант Array для indexOf через его прототип. Меня удивляет, что ArrayindexOf функционирует на NodeList, и было ли это намеренно или случайно.
@StevenLu Ваш первый вопрос: indexOf в NodeList не определен в спецификации DOM, даже в DOM4. Ваш последний пункт: это предназначено. Методы массива достаточно универсальны, чтобы работать практически с чем угодно, имеющим свойство length.
@StevenLu Это сделано намеренно. См. ECMA-262, издание 5 стр. 244 (145 в pdf), последнее примечание к разделу 15.4.4.14: «Функция indexOf намеренно общая; она не требует, чтобы ее значение это было объектом Множество. объекты для использования в качестве метода. Возможность успешного применения функции indexOf к объекту хоста зависит от реализации ".
За счет распределения массива его можно сократить до [].indexOf.call(children, el), если только это не выполняется с заявлением о совместимости браузера (хотя это меня удивит).
В настоящее время можно использовать [... e.childNodes].indexOf(elem).
@pat Ты мог ... Однако там проблема как в Комментарий JMM.
Итак, вы также можете сделать Array.from(e.childNodes).indexOf(elem)
Обратите внимание, что [].indexOf.call выделяет новый пустой массив, который после этого удаляется. [ ...e.childNodes].indexOf(elem) выделяет весь новый массив дочерним узлам, который затем отбрасывается. Оригинальное решение, напротив, не выделяет явно какие-либо новые данные где-либо, оно применяет существующую функцию к существующим данным.
Современный нативный подход может включать Array.from(e.children).indexOf(theChild)
Нет поддержки IE, но Edge работает: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
Разве вы не можете заменить
while(elem.previousSibling){k++;elem = elem.previousSibling;}наwhile(elem=elem.previousSibling){k++;}?