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

Vad*_*Vad 66 html javascript dom parent-child

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

UL
 LI
 LI
 LI - my index is 2
 LI
Run Code Online (Sandbox Code Playgroud)

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

所以,假设我有一个对象引用第三个LI,如上例所示.我怎么知道它是索引2?

谢谢.

jAn*_*ndy 79

你可以使用Array.prototype.indexOf.为此,我们需要在某种程度上将"演员" HTMLNodeCollection变成真实的Array.例如:

var nodes = Array.prototype.slice.call( document.getElementById('list').children );
Run Code Online (Sandbox Code Playgroud)

然后我们可以打电话:

nodes.indexOf( liNodeReference );
Run Code Online (Sandbox Code Playgroud)

例:

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

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

  • ES6 语法:`const index = [...el.parentNode.children].indexOf(el)` (4认同)
  • 注意:`.childNodes`和`.children`是不同的东西.`.children`是一个子集,仅列出所有`ElementNodes`. (3认同)
  • [`previousElementSibling`解决方案](http://stackoverflow.com/questions/11761881/javascript-dom-find-element-index-in-container#comment29654968_11762728)更好,因为它将排除文本节点并将返回索引你期望的元素. (2认同)
  • 我实际上更喜欢 `Array.from( el.parentNode.children ).indexOf( el );` 在那个实例上,只是为了可读性。 (2认同)

Tim*_*own 44

2017年更新

下面的原始答案假定OP想要包括非空文本节点和其他节点类型以及元素.我现在似乎不清楚这是否是一个有效的假设.

假设你只是想要元素索引,previousElementSibling现在得到了很好的支持(2012年不是这种情况),现在是明显的选择.以下(与此处的其他答案相同)将适用于IE <= 8以外的所有主要内容.

function getElementIndex(node) {
    var index = 0;
    while ( (node = node.previousElementSibling) ) {
        index++;
    }
    return index;
}
Run Code Online (Sandbox Code Playgroud)

原始答案

只要使用previousSibling,直到你击中null.我假设您要忽略仅限空格的文本节点; 如果要过滤其他节点,请相应调整.

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

  • +1与此处描述的任何其他方法相比,这是最快的.对于较新的浏览器,可以在没有这两个条件的情况下使用previousElementSibling. (6认同)
  • 没必要.这不够.每个人都知道你需要至少另外7个美女. (2认同)
  • 这是什么!/ ^\s*$/.test(node.data)究竟做到了什么? (2认同)

小智 25

我是怎么做的(2018年的版本?):

const index = [...el.parentElement.children].indexOf(el);
Run Code Online (Sandbox Code Playgroud)

Tadaaaam.而且,如果你想要考虑原始文本节点,你可以这样做:

const index = [...el.parentElement.childNodes].indexOf(el);
Run Code Online (Sandbox Code Playgroud)

我将子节点传播到数组中,因为它们是HTMLCollection(因此它们不能与indexOf一起使用).

小心你正在使用Babel或浏览器覆盖范围足以满足你需要实现的目标(想想扩展运算符,它基本上是一个Array.from后面的场景).

  • 当将 `[...el.parentElement.children]` 与打字稿一起使用时,会引发错误:_Type 'HTMLCollection' 不是数组类型或没有返回迭代器的 '[Symbol.iterator]()' 方法._ 在这种情况下,这种方法更好:`Array.from(el.parentElement.children)` (3认同)
  • 真的很酷!只需将 `Array.from` 分别添加到 childNodes `const index = [...Array.from(el.parentElement.children)].indexOf(el);` (2认同)
  • 如果用作面试的一部分 - 您应该提到 Array.from (或 [...] )将创建集合的浅表副本 - 而 Array.prototype.indexOf.call 不会。 (2认同)
  • @DavidDalBusco,您正在创建 2 个数组。如果您使用 Array.from 那么只需 `Array.from(el.parentElement.children).indexOf(el)` 就足够了。无需创建一个数组,然后将该数组分散到另一个数组中。另外,虽然“[...children]”很简洁,但它创建一个临时数组只是为了搜索它,然后丢弃临时数组。如果你想要速度,那么 Array.prototype.indexOf.call(el.parentElement.children, el) 应该更快,因为没有创建临时数组。速度并不总是很重要,大多数时候我都会选择“[...children]”。 (2认同)

Ale*_*kin 13

Array.prototype.indexOf.call(this.parentElement.children, this);
Run Code Online (Sandbox Code Playgroud)

或使用let声明.


Web*_*ner 9

对于just元素,这可用于在其兄弟元素中查找元素的索引:

function getElIndex(el) {
    for (var i = 0; el = el.previousElementSibling; i++);
    return i;
}
Run Code Online (Sandbox Code Playgroud)

请注意,previousElementSiblingIE <9不支持.

  • @RooticalV.:不确定你的意思。你是想问如果没有以前的兄弟姐妹会发生什么吗?在这种情况下,循环将自动退出,因为表达式“el = el.previousElementSibling”的值将为 false(因为它为 null)。或者您是想问如果在上面的代码中将“previousElementSibling”替换为“nextElementSibling”会发生什么?那么,在这种情况下,循环将计算仍在该元素后面的同级元素的数量。 (2认同)

rsp*_*lak 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]));
}?
Run Code Online (Sandbox Code Playgroud)

的jsfiddle


cal*_*oop 5

现代本机方法可以使用 'Array.from()' - 例如:`

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

`


Ngu*_* Vu 5

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