How to find the nearest common ancestors of two or more nodes?

前端 未结 14 1964
-上瘾入骨i
-上瘾入骨i 2020-11-30 04:03

Users selects two or more elements in a HTML page. What i want to accomplish is to find those elements\' common ancestors (so body node would be the common ancestor if none

14条回答
  •  青春惊慌失措
    2020-11-30 04:09

    Here's another pure method that uses element.compareDocumentPosition() and element.contains(), the former being a standards method and the latter being a method supported by most major browsers excluding Firefox:

    Comparing two nodes

    function getCommonAncestor(node1, node2) {
        var method = "contains" in node1 ? "contains" : "compareDocumentPosition",
            test   = method === "contains" ? 1 : 0x10;
    
        while (node1 = node1.parentNode) {
            if ((node1[method](node2) & test) === test)
                return node1;
        }
    
        return null;
    }
    

    Working demo: http://jsfiddle.net/3FaRr/ (using lonesomeday's test case)

    This should be, more or less, as efficient as possible since it is pure DOM and has only one loop.


    Comparing two or more nodes

    Taking another look at the question, I noticed the "or more" part of the "two or more" requirement had gone ignored by the answers. So I decided to tweak mine slightly to allow any number of nodes to be specified:

    function getCommonAncestor(node1 /*, node2, node3, ... nodeN */) {
        if (arguments.length < 2)
            throw new Error("getCommonAncestor: not enough parameters");
    
        var i,
            method = "contains" in node1 ? "contains" : "compareDocumentPosition",
            test   = method === "contains" ? 1 : 0x0010,
            nodes  = [].slice.call(arguments, 1);
    
        rocking:
        while (node1 = node1.parentNode) {
            i = nodes.length;    
            while (i--) {
                if ((node1[method](nodes[i]) & test) !== test)
                    continue rocking;
            }
            return node1;
        }
    
        return null;
    }
    

    Working demo: http://jsfiddle.net/AndyE/3FaRr/1

提交回复
热议问题