【问题标题】:What's the best way to find the first common parent of two DOM nodes in javascript?在javascript中找到两个DOM节点的第一个公共父节点的最佳方法是什么?
【发布时间】:2010-03-16 10:59:30
【问题描述】:

我的问题正是如此,但在上下文中我想检查选择对象,比较 anchorNode 和 focusNode,如果它们不同,则找到第一个公共父元素。

var selected = window.getSelection();
var anchor = selection.anchorNode;
var focus = selection.focusNode;

if ( anchor != focus ) {
   // find common parent...
}

【问题讨论】:

    标签: javascript dom selection getselection


    【解决方案1】:

    我会尝试这样的事情,假设没有 JS 库:

    function findFirstCommonAncestor(nodeA, nodeB, ancestorsB) {
        var ancestorsB = ancestorsB || getAncestors(nodeB);
        if(ancestorsB.length == 0) return null;
        else if(ancestorsB.indexOf(nodeA) > -1) return nodeA;
        else if(nodeA == document) return null;
        else return findFirstCommonAncestor(nodeA.parentNode, nodeB, ancestorsB);
    }
    

    使用此实用程序:

    function getAncestors(node) {
        if(node != document) return [node].concat(getAncestors(node.parentNode));
        else return [node];
    }
    
    if(Array.prototype.indexOf === undefined) {
        Array.prototype.indexOf = function(element) {
            for(var i=0, l=this.length; i<l; i++) {
                if(this[i] == element) return i;
            }
            return -1;
        };
    }
    

    那你可以拨打findFirstCommonAncestor(myElementA, myElementB)

    【讨论】:

    • 感谢图书馆的免费版本,尽管你们都帮了大忙!
    【解决方案2】:

    这种方式相当简单:

    var fp = $(focus).parents();
    var ap = $(anchor).parents();
    for (var i=0; i<ap.length; i++) {
      if (fp.index(ap[i]) != -1) {
        // common parent
      }
    }
    

    循环遍历一个元素的parents(),并使用index() 查看它们是否包含在另一个元素的parents() 中,直到找到匹配项(或不匹配)。

    【讨论】:

    • 非常整洁 - 我可能需要在这个项目的案例中获取一些 jquery,现在开始看起来值得。
    • @sanchothefat 哦,我的错,对不起,出于某种原因,我认为您的问题与 jQuery 相关。
    • 不用担心。这些天(或应该)几乎所有的 javascript 都与 jquery 相关
    【解决方案3】:

    // 看起来应该相当简单,即使没有库或 indexOf

    document.commonParent= function(a, b){
     var pa= [], L;
     while(a){
      pa[pa.length]=a;
      a= a.parentNode;
     }
     L=pa.length;
     while(b){  
      for(var i=0; i<L; i++){
       if(pa[i]==b) return b;
      }
      b= b.parentNode;
     }
    }
    

    【讨论】:

      【解决方案4】:

      由于这个问题和接受的答案都非常过时,我想建议使用更现代的 DOM API,Range

      function findFirstCommonAncestor(nodeA, nodeB) {
          let range = new Range();
          range.setStartBefore(nodeA);
          range.setEndAfter(nodeB);
          // There's a compilication, if nodeA is positioned after
          // nodeB in the document, we created a collapsed range.
          // That means the start and end of the range are at the
          // same position. In that case `range.commonAncestorContainer`
          // would likely just be `nodeB.parentNode`.
          if(range.collapsed) {
              // The old switcheroo does the trick.
              range.setStartBefore(nodeB);
              range.setEndAfter(nodeA);
          }
          return range.commonAncestorContainer;
      }
      

      【讨论】:

        【解决方案5】:

        有一个很好的 DOM API:compareDocumentPosition

        事情是这样的:

            /**
             * Returns closest parent element for both nodes.
             */
            function getCommonParent(one, two){
                let parent = one.parentElement;
                if(one === two) { //both nodes are the same node.
                    return parent;
                }
                const contained = Node.DOCUMENT_POSITION_CONTAINED_BY;
                let docpos = parent.compareDocumentPosition(two);
        
                while(parent && !(docpos & contained)) {
                    parent = parent.parentElement;
                    docpos = parent.compareDocumentPosition(two);
                }
                return parent;
            }
        

        【讨论】:

          猜你喜欢
          • 2015-08-07
          • 2011-09-01
          • 2011-01-05
          • 1970-01-01
          • 1970-01-01
          • 2013-11-06
          • 1970-01-01
          • 2017-09-14
          • 1970-01-01
          相关资源
          最近更新 更多