JavaScript DOM:在容器中查找元素索引


78

我需要通过对象引用在其容器内找到元素的索引。奇怪的是,我找不到简单的方法。请不要jQuery-只有DOM。

UL
 LI
 LI
 LI - my index is 2
 LI

是的,我可以为每个元素分配ID并遍历所有节点以匹配ID,但这似乎是一个不好的解决方案。没有更好的东西吗?

因此,就像上面的示例一样,我有一个对第三LI的对象引用。我怎么知道它是索引2?

谢谢。


您如何获取索引?悬停..等等?
克莱德·罗伯

1
为什么不对li引用执行previousSibling,直到您点击null?
Ashwin Prabhu 2012年


我认为将自定义属性添加到li元素会很容易。例如,<li index =“ 0”>,<li index =“ 1”>,您可以轻松访问它。
HENG Vongkol 2015年

Answers:


93

您可以使用Array.prototype.indexOf。为此,我们需要在某种程度上“铸成” HTMLNodeCollectiontrue 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仅列出所有子集。
伊恩·克拉克

2
previousElementSibling解决方案更好,因为它将排除文本节点,并返回所需元素的索引。
Dan Dascalescu 2014年

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与此处描述的任何其他方法相比,这是最快的。对于较新的浏览器,可以在没有这两个条件的情况下使用previousElementSibling。
Akash Kava 2013年

@ bjb568:您的意思是有一组不必要的括号吗?
Tim Down

2
没必要。这不够。每个人都知道,您至少还需要7个美容品。
bjb568 2014年

@ bjb568:最好也将其关闭。
Tim Down

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。)。


可以确认这是正常的。无需循环任何内容。
Fabian von Ellerts,

最佳答案IMO,简洁明了
Aaria Carter-Weir

1
真酷!刚Array.from分别添加到childNodes中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”的值将为false(因为它为null)。还是您想问一下,如果在上面的代码中将“ 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 2012年

previousElementSibling解决方案更好,因为它将排除文本节点,并返回所需元素的索引。
Dan Dascalescu 2014年

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>中的,<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;
        }
    }

}

演示版


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

0

另一个仅使用基本循环和索引检查的示例

的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


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);
                }
            }
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.