Подтвердить что ты не робот

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

Мне нужно найти индекс элемента внутри его контейнера по ссылке на объект. Как ни странно, я не могу найти простой способ. Нет jQuery пожалуйста - только DOM.

UL
 LI
 LI
 LI - my index is 2
 LI

Да, я мог бы присваивать идентификаторы каждому элементу и перебирать все узлы в соответствии с ID, но это кажется плохим решением. Разве нет ничего лучше?

Итак, скажем, у меня есть ссылка на объект для третьего LI, как в приведенном выше примере. Как узнать, что это индекс 2?

Спасибо.

4b9b3361

Ответ 1

Вы можете использовать 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>

Ответ 2

Обновление 2017

В первоначальном ответе ниже предполагается, что OP хочет включить непустой текст node и другие node типы, а также элементы. Мне теперь не ясно, из вопроса, является ли это допустимым предположением.

Предполагая, что вам просто нужен индекс элемента, 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;
}

Ответ 3

Вот как я это делаю (версия 2018?):

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

Tadaaaam. И если вы захотите также рассмотреть исходные текстовые узлы, вы можете сделать это вместо этого:

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

Я распространяю детей на массив, поскольку они являются HTMLCollection (поэтому они не работают с indexOf).

Будьте осторожны с тем, что вы используете Babel или что покрытие браузера достаточно для того, что вам нужно достичь (мысли о операторе распространения, который в основном представляет собой Array.from за сценой).

Ответ 4

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

Или используйте оператор let.

Ответ 5

Для простых элементов это может быть использовано для поиска индекса элемента среди его элементов-братьев:

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

Обратите внимание, что previousElementSibling не поддерживается в IE < 9.

Ответ 6

Вы можете использовать это, чтобы найти индекс элемента:

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

Ответ 7

Пример создания массива из 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>

Ответ 8

В современном родном подходе можно использовать "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>

Ответ 9

Вы можете выполнить итерацию через <li> в <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;
        }
    }

}

Демо

Ответ 10

Если вы хотите записать это компактное все, что вам нужно:

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

Мы просто перебираем элементы в родительском node, останавливаясь, когда находим ваш элемент.

Вы также можете легко сделать:

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

если это все, что вы хотите просмотреть.

Ответ 11

Другой пример: просто использовать базовый цикл и проверку индекса

HTML

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

JavaScript запускается onload/ready или после отображения 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

Ответ 12

Просто передайте ссылку на объект на следующую функцию, и вы получите индекс

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);
                }
            }
        }
    }
}

Ответ 13

    const nodes = Array.prototype.slice.call( el.parentNode.childNodes );
    const index = nodes.indexOf(el);
    console.log('index = ', index);