指定body节点下的任意元素节点,如何快速算出它是body的第几代,第几个子孙元素?

我们开发时有一个需求,让我几乎崩溃。
需求总结后就是:
指定body节点下的任意元素节点,算出它是body节点的第几个儿子的,第几个孙子。这个关系可以很长。比如某些很深的元素节点,可能结论是:某元素节点是body节点的第2个儿子的第3个儿子的第1个儿子的第9个儿子。

(PS:textNode要跳过,只计算elementNode)

我实在搞不定了,搜资料也没找到对口的,求大神帮忙,分享一些资料也好啊。

阅读 3k
3 个回答
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <div></div>
    <div>
        <div>
            <span>
      你是一个
      <a href="http://www.baidu.com">链接</a>
      吧
    </span>
            <span>
      另一个 <a href="http://mail.163.com">链接</a>
    </span>
        </div>
    </div>
    <ul></ul>
    <ul>
        <li>没事</li>
        <li>
            <ol>
                <li>第0</li>
                <li>第1</li>
                <li>第3是个 <a href="#" id='lastA'>链接</a></li>
            </ol>
        </li>
    </ul>
</body>
<script>
function Path(el) {
    if (!el) return;
    const res = [{
        el: el,
        index: findIndex(el),
        type: el.nodeName
    }];
    while (el.parentNode && el.parentNode !== document.documentElement) {
        res.push({
            el: el.parentNode,
            index: findIndex(el.parentNode),
            type: el.parentNode.nodeName
        });
        el = el.parentNode
    };
    return res.reverse().reduce(function(prev, item) {
        prev += '第' + item.index + '个' + item.type + '下'
        return prev
    }, '').replace(/下$/, '')
}

function findIndex(el) {
    let index = 1;
    while (el.previousSibling) {
        if (el.previousSibling.nodeType === 1 && el.parentNode !== document.documentElement)
            index++;

        el = el.previousSibling
    }
    return index
}
console.log(Path(document.getElementById('lastA')))
</script>

</html>

如果用 jQuery 还是比较好处理的(不过这种处理性能肯定不会好)

function findIndexes(jo) {
    var parents = jo.parentsUntil("body");
    return parents.map(function() {
        return $(this).index();
    }).toArray().reverse();
}

https://jsfiddle.net/7sak70gu/

  1. 这个需求我觉得从安置dom节点的时候就应该考虑到,比如说dom节点与一个数据结构相对应,或者对dom节点做hash(没错就是Vitrual DOM的思路)

  2. 不然最优的方案只能是逆向宽搜(通过父节点遍历到目前是第几个,如果父节点不是body就继续这步骤),不过,读取DOM节点的代价也是高昂的不亚于操作DOM节点,适用于DOM数量级较小的页面

  3. 如果上了React等,那可以简化一点,其实和第一个数据相同

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题