2010-11-04 47 views
9

的第一個共享父可以說我有這個DOM結構發現兩個元素

<body> 
    <p> 
     Hello 
     <i>how <b>are</b> you</i> 
     and 
     <i>what <b>are <tt>you</tt> going</b> to</i> 
     eat tonight? 
    </p> 
</body> 

使用jQuery我想知道的

<b>are</b> 

第一共用家長和

<tt>you</tt> 

從下到上這將是< p>而不是< body>標記。

有關如何確定使用jQuery的第一個共享父項的任何想法?

+0

最近的共同祖先。感覺像我正在學習遺傳學或其他東西! – jball 2010-11-04 17:59:43

回答

9

像這樣:

$(a).parents().filter(function() { return jQuery.contains(this, b); }).first(); 

b如果是一個選擇器(而不是一個DOM元素),可以將其改變爲:

$(a).closest(':has(b)'); 

這是短,但慢得多。

ab的順序是不相關的;如果b距父母更近,則會更快。

+0

這是行不通的,你可以在這裏測試它:http://www.jsfiddle.net/nick_craver/a7hgu/你必須在'.filter()'函數中'返回'來獲得任何結果。 – 2010-11-04 18:07:44

+0

@Nick:固定;謝謝。我懷疑這會比你的版本更快,因爲'contains'調用了一個本地方法(請參閱jQuery源代碼)。我懶得檢查。 – SLaks 2010-11-04 18:09:35

+0

@SLaks - *如果*瀏覽器支持,是的,雖然你不能直接在這裏使用選擇器,所以它有點混亂,取決於你在做什麼(在一個循環或不循環)。只是一個想法:如果'.closest()'帶着一組元素來過濾它,那麼在這裏會很好... – 2010-11-04 18:14:32

5

你可以用.filter()結合.parents(),像這樣:

$("b:first").parents().filter($("tt").parents()).first() 
//or more generic: 
$(elem1).parents().filter($(elem2).parents()).first() 

這得到所有共享的父母,那麼你可以採取的.first().last() ...什麼需要真實。

You can test it here。請注意,這比.has()快得多,因爲我們只比較2個DOM元素集,而不是遞歸地比較許多元素集。另外,結果集將按照文檔中的順序排列,在此示例中爲<p>,然後爲<body>

+1

更好地將樹行走到根,並試圖找到第一場比賽,而不是在每個子樹中進行全面搜索。 – Gumbo 2010-11-04 18:11:06

0

非jQuery的版本:

var arrayContains = Array.prototype.indexOf ? 
    function(arr, val) { 
     return arr.indexOf(val) > -1; 
    }: 

    function(arr, val) { 
     var i = arr.length; 
     while (i--) { 
      if (arr[i] === val) { 
       return true; 
      } 
     } 
     return false; 
    }; 


function getCommonAncestor(node1, node2) { 
    var ancestors = [], n; 
    for (n = node1; n; n = n.parentNode) { 
     ancestors.push(n); 
    } 

    for (n = node2; n; n = n.parentNode) { 
     if (arrayContains(ancestors, n)) { 
      return n; 
     } 
    } 

    return null; 
} 
0

這裏是一個非常簡單的非jQuery的解決方案:

function sharedParent (elem1, elem2) { 
for (; elem1!= null; elem1=elem1.parentNode) { 
    for (var e2=elem2; e2!= null; e2=e2.parentNode) 
    if (elem1 == e2) return elem1; 
    } 
return null; 
} 
0
jQuery(function(){ 

    var elem1 = jQuery("#a"); 
    var elem2 = jQuery("#b"); 

    var foo1 = elem1.parents().has(elem2).first().attr("tagName"); 
    var foo2 = elem1.closest(":has(" + elem2.selector + ")").first().attr("tagName"); 

    alert(foo1); 
    alert(foo2); 


}); 

JSBIN