JavaScript DOM: найдите элементный индекс в контейнере
Мне нужно найти индекс элемента внутри его контейнера по ссылке на объект. Как ни странно, я не могу найти простой способ. Нет jQuery пожалуйста - только DOM.
UL
LI
LI
LI - my index is 2
LI
Да, я мог бы присваивать идентификаторы каждому элементу и перебирать все узлы в соответствии с ID, но это кажется плохим решением. Разве нет ничего лучше?
Итак, скажем, у меня есть ссылка на объект для третьего LI, как в приведенном выше примере. Как узнать, что это индекс 2?
Спасибо.
Ответы
Ответ 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);