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

Posted

技术标签:

【中文标题】JavaScript DOM:在容器中查找元素索引【英文标题】:JavaScript DOM: Find Element Index In Container 【发布时间】:2012-07-30 12:06:41 【问题描述】:

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

UL
 LI
 LI
 LI - my index is 2
 LI

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

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

谢谢。

【问题讨论】:

需要如何获取索引?悬停..等?? 为什么不在 li 引用上执行 previousSibling 直到你命中 null? Finding DOM node index 的可能重复项 我认为如果您将自定义属性添加到 li 元素会很容易。例如、 ,你可以轻松访问。 【参考方案1】:
    const nodes = Array.prototype.slice.call( el.parentNode.childNodes );
    const index = nodes.indexOf(el);
    console.log('index = ', index);

【讨论】:

【参考方案2】:

这是我的做法(2018 版?)

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

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

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

我将孩子分散到一个数组中,因为它们是一个 htmlCollection(因此它们不适用于 indexOf)。

请注意您正在使用 Babel,或者浏览器覆盖范围足以满足您的需要(考虑扩展运算符,它基本上是一个 Array.from 幕后)。

【讨论】:

可以确认这是有效的。无需循环任何内容。 最佳答案 IMO,简洁明了 真的很酷!刚刚将Array.from分别添加到childNodes const index = [...Array.from(el.parentElement.children)].indexOf(el); 如果用作采访的一部分 - 你应该提到 Array.from (或 [...] )将创建集合的浅表副本 - 而 Array.prototype.indexOf.call 不会。 当使用 [...el.parentElement.children] 和 typescript 时,会引发错误:Type 'HTMLCollection' 不是数组类型或没有返回的 '[Symbol.iterator]()' 方法一个迭代器。 在这种情况下,这种方法更好:Array.from(el.parentElement.children)【参考方案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>

`

【讨论】:

【参考方案4】:

您可以遍历&lt;ul&gt; 中的&lt;li&gt;s,并在找到合适的时候停止。

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;
        
    


Demo

【讨论】:

【参考方案5】:

您可以使用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>

【讨论】:

注意:.childNodes.children 是不同的东西。 .children 是一个子集,只是所有 ElementNodes 的列表。 previousElementSibling solution 更好,因为它将排除文本节点并返回您期望的元素的索引。 ES6 语法:const index = [...el.parentNode.children].indexOf(el) 我实际上更喜欢 Array.from( el.parentNode.children ).indexOf( el ); 在那个实例上,只是为了可读性。【参考方案6】:

2017 年更新

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

假设您只需要元素索引,previousElementSibling 现在得到了很好的支持(2012 年不是这种情况),现在是显而易见的选择。以下(与此处的其他一些答案相同)将适用于除 IE

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;

【讨论】:

+1 与此处描述的任何其他方法相比,这是最快的。对于较新的浏览器,previousElementSibling 可以在没有这两个条件的情况下使用。 @bjb568:你的意思是有一组不必要的括号吗? 没有必要。这不够。每个人都知道,为了美丽,你至少需要另外 7 个。 @bjb568:最好也关闭它们。 这 !/^\s*$/.test(node.data) 到底是做什么的?【参考方案7】:

如果你想写得紧凑,你只需要:

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

我们只是循环遍历父节点中的元素,当我们找到您的元素时停止。您也可以轻松地这样做:

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

如果这就是你想要查看的全部内容。

【讨论】:

【参考方案8】:
Array.prototype.indexOf.call(this.parentElement.children, this);

或者使用let 声明。

【讨论】:

@citykid,当然,它更简洁,但创建一个临时数组只是为了访问该数组的函数是愚蠢的。【参考方案9】:

从 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>

【讨论】:

【参考方案10】:

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

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

注意previousElementSibling 在 IE

【讨论】:

如果不是上一个兄弟而是下一个怎么办? @RooticalV.:不确定你的意思。你的意思是问如果没有以前的兄弟姐妹会发生什么?在这种情况下,循环将自动退出,因为表达式“el = el.previousElementSibling”的值将是假的(因为它是空的)。或者你的意思是问如果你在上面的代码中将“previousElementSibling”替换为“nextElementSibling”会发生什么?好吧,在这种情况下,循环将计算仍然跟随元素的兄弟姐妹的数量。【参考方案11】:

只需将对象引用传递给以下函数即可获得索引

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

【讨论】:

【参考方案12】:

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

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

【讨论】:

【参考方案13】:

您可以使用它来查找元素的索引:

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

【讨论】:

我误解了这个问题。已编辑! previousElementSibling solution 更好,因为它将排除文本节点并返回您期望的元素的索引。

以上是关于JavaScript DOM:在容器中查找元素索引的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 学习-27.查找HTML DOM节点(元素)

JavaScript HTML DOM

JavaScript DOM基础:查找元素

使用 JavaScript 获取 2 个 DOM 元素之间的相对位置

在给定 CSS 选择器的情况下查找 DOM 元素的 Vanilla JavaScript 函数

javascript dom查找元素常用方法