2010-11-04 20 views
9

Finding Lets ich diese DOM-Struktur sagenden ersten gemeinsamen Eltern von zwei Elementen

<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> 

Mit jQuery ich die ersten gemeinsamen Elternteil des

<b>are</b> 

und die

kennen lernen wollen
<tt>you</tt> 

Von unten nach oben wäre dies das < p> nicht das < body> -Tag.

Irgendwelche Ideen, wie man den ersten geteilten Elternteil unter Verwendung von jQuery bestimmt?

+0

letzten gemeinsamen Vorfahren. Fühle mich wie ich Genetik oder etwas studiere! – jball

Antwort

9

So:

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

Wenn b ein Selektor ist (im Gegensatz zu einem DOM-Elemente entgegengesetzt), können Sie es ändern:

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

Dies ist kürzer, aber wesentlich langsamer. Die Reihenfolge a und b ist irrelevant. Wenn b näher am Eltern ist, wird es schneller sein.

+0

Dies funktioniert nicht, Sie können es hier testen: http://www.jsfiddle.net/nick_craver/a7hgu/ Sie müssen in einer '.filter()' Funktion zurückkehren, um irgendwelche Ergebnisse zu erhalten. –

+0

@Nick: Fest; Vielen Dank. Ich vermute, dass dies schneller als deine Version sein wird, da 'contains 'eine native Methode aufruft (siehe die jQuery-Quelle). Ich bin zu faul, um nachzusehen. – SLaks

+0

@SLaks - * Wenn * der Browser es ja unterstützt, obwohl Sie einen Selektor nicht direkt verwenden können, so ist es ein bisschen unordentlicher, hängt davon ab, was Sie damit machen (in einer Schleife oder nicht). Nur ein Gedanke: wäre gut hier, wenn '.closes()' eine Reihe von Elementen zu filtern, wie es geht ... –

5

können Sie kombinieren .parents() mit .filter(), wie folgt aus:

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

Dies wird alle gemeinsamen Eltern, können Sie dann die .first() nehmen oder .last() ... was auch immer gebraucht wird.

You can test it here. Beachten Sie, dass dies viel schneller ist als .has(), da wir nur 2 DOM-Elementsets vergleichen und nicht viele rekursiv vergleichen. Der resultierende Satz wird auch in der Reihenfolge sein, in der er das Dokument hochfährt, in diesem Beispiel <p>, dann <body>.

+1

Viel besser, den Baum bis zur Wurzel zu laufen und zu versuchen, das erste Match zu finden, als eine vollständige Suche in jedem Teilbaum durchzuführen. – Gumbo

0

Non-jQuery-Version:

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

Hier ist eine sehr einfache, nicht jquery Lösung:

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

Verwandte Themen