查找父节点中子节点索引的最快方法

gki*_*ely 33 html javascript dom

我想找到具有id的子div的索引'whereami'.

<div id="parent">
   <div></div>
   <div></div>
   <div id="whereami"></div>
   <div></div>
</div>
Run Code Online (Sandbox Code Playgroud)

目前我正在使用此函数来查找子项的索引.

function findRow(node){
    var i=1;
    while(node.previousSibling){
        node = node.previousSibling;
        if(node.nodeType === 1){
            i++;
        }
    }
    return i; //Returns 3
}

var node = document.getElementById('whereami'); //div node to find
var index = findRow(node);
Run Code Online (Sandbox Code Playgroud)

小提琴:http://jsfiddle.net/grantk/F7JpH/2/

问题
当有数千个div节点时,while循环必须遍历每个div来计算它们.这可能需要一段时间.

有没有更快的方法来解决这个问题?

*请注意,id将更改为不同的div节点,因此需要能够重新计算.

Ja͢*_*͢ck 38

出于好奇,我针对jQuery .index()和我的下面的代码运行了你的代码:

function findRow3(node)
{
    var i = 1;
    while (node = node.previousSibling) {
        if (node.nodeType === 1) { ++i }
    }
    return i;
}
Run Code Online (Sandbox Code Playgroud)

跳转到jsperf结果

事实证明,jQuery比你的实现(在Chrome/Mac上)大约慢50%,并且可以说它高出1%.

编辑

不能完全放弃这个,所以我又增加了两个方法:

使用Array.indexOf

[].indexOf.call(node.parentNode.children, node);
Run Code Online (Sandbox Code Playgroud)

我的早期实验代码的改进,如HBP的答案所示,DOMNodeList被视为一个数组,它用于Array.indexOf()确定.parentNode.children其中所有元素的位置.我的第一次尝试是使用.parentNode.childNodes但由于文本节点而导致错误的结果.

使用previousElementSibling

受用户1689607的回答启发,最近的浏览器除了.previousSibling被调用之外还有另一个属性.previousElementSibling,它将两个原始陈述合二为一.IE <= 8没有此属性,但.previousSibling已经如此,因此功能检测将起作用.

(function() {
    // feature detection
    // use previousElementSibling where available, IE <=8 can safely use previousSibling
    var prop = document.body.previousElementSibling ? 'previousElementSibling' : 'previousSibling';

    getElementIndex = function(node) {
        var i = 1;
        while (node = node[prop]) { ++i }
        return i;
    }
Run Code Online (Sandbox Code Playgroud)

结论

Array.indexOf()IE <= 8浏览器不支持使用,仿真速度不够快; 但是,它确实提高了20%的性能.

使用特征检测并.previousElementSibling提高了7倍(在Chrome上),我还没有在IE8上测试它.


HBP*_*HBP 5

通过选择Array indexOf您可以使用:

  var wmi = document.getElementById ('whereami');
  index = [].indexOf.call (wmi.parentNode.children, wmi);
Run Code Online (Sandbox Code Playgroud)

[仅在Chrome浏览器上测试]