JavaScript DOM: знайти індекс елемента в контейнері


78

Мені потрібно знайти індекс елемента всередині його контейнера за посиланням на об’єкт. Дивно, але я не можу знайти легкого шляху. Жодного jQuery, будь ласка - лише DOM.

UL
 LI
 LI
 LI - my index is 2
 LI

Так, я міг би присвоїти ідентифікатори кожному елементу та прокрутити всі вузли відповідно до ідентифікатора, але це здається поганим рішенням. Хіба немає чогось приємнішого?

Отже, скажімо, у мене є посилання на об’єкт третього LI, як у прикладі вище. Як я знаю, що це індекс 2?

Дякую.


Як потрібно отримати індекс? навести .. і т.д. ??
Clyde Lobo

1
чому б не виконати попередню Sibling для посилання li, поки ви не натиснете нуль?
Ашвін Прабху,


Думаю, було б легко, якщо ви додасте спеціальний атрибут до елемента li. Наприклад, <li index = "0">, <li index = "1">, і ви можете легко отримати до них доступ.
HENG Vongkol

Відповіді:


94

Ви можете використовувати Array.prototype.indexOf. Для цього нам потрібно дещо "перекинути" це HTMLNodeCollectionна справжнє Array. Наприклад:

var nodes = Array.prototype.slice.call( document.getElementById('list').children );

Тоді ми могли просто зателефонувати:

nodes.indexOf( liNodeReference );

Приклад:

var nodes = Array.prototype.slice.call( document.getElementById('list').children ),
    liRef = document.getElementsByClassName('match')[0];

console.log( nodes.indexOf( liRef ) );
<ul id="list">
    <li>foo</li>
    <li class="match">bar</li>
    <li>baz</li>    
</ul>


3
Примітка: .childNodesі .childrenце різні речі. .children- це підмножина, лише список усіх ElementNodes.
Ian Clark

2
previousElementSiblingРішення краще , тому що це дозволить виключити текстові вузли і повертає індекс елемента , який ви очікуєте.
Дан Даскалеску,

3
Синтаксис ES6:const index = [...el.parentNode.children].indexOf(el)
ESR

Насправді я б віддав перевагу саме Array.from( el.parentNode.children ).indexOf( el );такому екземпляру, лише для читабельності.
jAndy

52

Оновлення 2017 року

Оригінальна відповідь нижче передбачає, що OP хоче включати непустий текстовий вузол та інші типи вузлів, а також елементи. Зараз мені не здається зрозумілим із питання, чи є це вірним припущенням.

Якщо припустити, що ви просто хочете індекс елемента, previousElementSiblingвін тепер добре підтримується (чого не було у 2012 році) і є очевидним вибором зараз. Наступне (що збігається з деякими іншими відповідями тут) буде працювати у всьому, крім IE <= 8.

function getElementIndex(node) {
    var index = 0;
    while ( (node = node.previousElementSibling) ) {
        index++;
    }
    return index;
}

Оригінальна відповідь

Просто використовуйте, previousSiblingпоки не вдарите null. Я припускаю, що ви хочете ігнорувати текстові вузли, що містять лише пробіли; якщо ви хочете відфільтрувати інші вузли, налаштуйте відповідно.

function getNodeIndex(node) {
    var index = 0;
    while ( (node = node.previousSibling) ) {
        if (node.nodeType != 3 || !/^\s*$/.test(node.data)) {
            index++;
        }
    }
    return index;
}

6
+1 Це найшвидше порівняно з будь-яким іншим методом, описаним тут. Для новішого браузера попередній ElementSibling можна використовувати без цих двох умов.
Akash Kava

@ bjb568: Ваша думка, що є набір непотрібних дужок?
Тім Даун

2
Не зайвий. Цього не достатньо. Всім відомо, що для краси вам потрібні принаймні ще 7.
bjb568

@ bjb568: Можливо, найкраще їх також закрити.
Тім Даун

3
що це робить! / ^ \ s * $ /. test (node.data)?
maxlego

48

Ось як я роблю (версія 2018?) :

const index = [...el.parentElement.children].indexOf(el);

Тадаааам. І якщо ви коли-небудь захочете також розглянути вузли необробленого тексту, замість цього ви можете зробити це:

const index = [...el.parentElement.childNodes].indexOf(el);

Я розподіляю дітей у масив, оскільки вони є HTMLCollection (отже, вони не працюють з indexOf).

Будьте обережні, що ви використовуєте Babel або що покриття браузера достатньо для того, що вам потрібно досягти (думки про оператор поширення, який в основному є Array.from the scene).


Можна підтвердити, що це працює. Не потрібно нічого цикувати.
Фабіан фон Еллерц,

Найкраща відповідь IMO, приємно і лаконічно
Aaria Carter-Weir

1
Дійсно здорово! Щойно додано Array.fromдо дочірніх вузлів відповідноconst index = [...Array.from(el.parentElement.children)].indexOf(el);
David Dal Busco

1
Якщо використовується як частина інтерв’ю - вам слід згадати, що Array.from (або [...]) створить мілку копію колекції - тоді як Array.prototype.indexOf.call не буде звичним.
CWright

19
Array.prototype.indexOf.call(this.parentElement.children, this);

Або скористайтеся letзаявою.


@citykid, звичайно, це лаконічніше, але нерозумно створювати тимчасовий масив лише для доступу до функції цього масиву.
gman

10

Для просто елементів це може бути використано для пошуку індексу елемента серед його братських елементів:

function getElIndex(el) {
    for (var i = 0; el = el.previousElementSibling; i++);
    return i;
}

Зверніть увагу, що previousElementSiblingIE <9 не підтримує.


1
Що робити, якщо це буде не попередній брат, а наступний?
Rootical V.

@RooticalV .: Не знаю, що ти маєш на увазі. Ви хотіли запитати, що трапиться, якщо немає попереднього брата або сестри? У цьому випадку цикл автоматично вийде, оскільки значення виразу "el = el.previousElementSibling" буде хибним (оскільки воно є нульовим). Або ви мали намір запитати, що станеться, якщо ви заміните "previousElementSibling" на "nextElementSibling" у наведеному вище коді? Ну, у цьому випадку цикл буде рахувати кількість братів і сестер, які все ще стежать за елементом.
HammerNL

8

Ви можете використовувати це, щоб знайти індекс елемента:

Array.prototype.indexOf.call(yourUl, yourLi)

Це, наприклад, реєструє всі індекси:

var lis = yourList.getElementsByTagName('li');
for(var i = 0; i < lis.length; i++) {
    console.log(Array.prototype.indexOf.call(lis, lis[i]));
}​

JSFIDDLE


Я неправильно інтерпретував питання. Відредаговано!
rsplak

previousElementSiblingРішення краще , тому що це дозволить виключити текстові вузли і повертає індекс елемента , який ви очікуєте.
Дан Даскалеску,

3

Сучасний рідний підхід може використовувати 'Array.from ()' - наприклад: `

const el = document.getElementById('get-this-index')
const index = Array.from(document.querySelectorAll('li')).indexOf(el)
document.querySelector('h2').textContent = `index = ${index}`
<ul>
  <li>zero
  <li>one
  <li id='get-this-index'>two
  <li>three
</ul>
<h2></h2>

`


2

Приклад створення масиву з HTMLCollection

<ul id="myList">
    <li>0</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

<script>
var tagList = [];

var ulList = document.getElementById("myList");

var tags   = ulList.getElementsByTagName("li");

//Dump elements into Array
while( tagList.length != tags.length){
    tagList.push(tags[tagList.length])
};

tagList.forEach(function(item){
        item.addEventListener("click", function (event){ 
            console.log(tagList.indexOf( event.target || event.srcElement));
        });
}); 
</script>

1

Якщо ви хочете написати це компактно, все, що вам потрібно:

var i = 0;
for (;yourElement.parentNode[i]!==yourElement;i++){}
indexOfYourElement = i;

Ми просто перебираємо елементи в батьківському вузлі, зупиняючись, коли знаходимо ваш елемент.

Ви також можете легко зробити:

for (;yourElement.parentNode.getElementsByTagName("li")[i]!==yourElement;i++){}

якщо це все, що ви хочете переглянути.


1

Ви можете перебирати <li>s в <ul>і зупинятися, коли знайдете потрібний.

function getIndex(li) {
    var lis = li.parentNode.getElementsByTagName('li');
    for (var i = 0, len = lis.length; i < len; i++) {
        if (li === lis[i]) {
            return i;
        }
    }

}

Демо



0

Ще один приклад просто використання базового циклу та перевірки індексу

HTML

<ul id="foo">
    <li>0</li>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

JavaScript працює при завантаженні / готовому або після відображення ul

var list = document.getElementById("foo"),
    items = list.getElementsByTagName("li");

list.onclick = function(e) {
    var evt = e || window.event,
    src = evt.target || evt.srcElement;
    var myIndex = findIndex(src);
    alert(myIndex);
};

function findIndex( elem ) {
    var i, len = items.length;
    for(i=0; i<len; i++) {
        if (items[i]===elem) {
            return i;
        }
    }
    return -1;
}

Приклад запуску

jsFiddle


0

Просто передайте посилання на об'єкт наступній функції, і ви отримаєте індекс

function thisindex(elm) 
{ 
    var the_li = elm; 
    var the_ul = elm.parentNode; 
    var li_list = the_ul.childNodes; 

    var count = 0; // Tracks the index of LI nodes

    // Step through all the child nodes of the UL
    for( var i = 0; i < li_list.length; i++ )
    {
        var node = li_list.item(i);
        if( node )
        {
        // Check to see if the node is a LI
            if( node.nodeName == "LI" )
            {
            // Increment the count of LI nodes
                count++;
            // Check to see if this node is the one passed in
                if( the_li == node )
                {
                    // If so, alert the current count
                    alert(count-1);
                }
            }
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.