2010-11-04 7 views
9

Diciamo che ho questa struttura DOMTrovare il primo genitore condiviso da due elementi

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

utilizzando jQuery voglio conoscere il genitore PRIMO condivisa del

<b>are</b> 

e la

<tt>you</tt> 

Dal basso verso l'alto questo sarebbe il < p> non il tag < body>.

Tutte le idee su come determinare il primo genitore condiviso utilizzando jQuery?

+0

più recente antenato comune. Mi sento come se stessi studiando genetica o qualcosa del genere! – jball

risposta

9

Ti piace questa:

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

Se b è un selettore (al contrario di un elemento DOM), è possibile modificarla in:

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

Questo è più breve, ma sostanzialmente più lento.

L'ordine di a e b è irrilevante; se b è più vicino al genitore, sarà più veloce.

+0

Questo non funzionerà, puoi testarlo qui: http://www.jsfiddle.net/nick_craver/a7hgu/ devi 'return' in una funzione' .filter() 'per ottenere qualsiasi risultato. –

+0

@Nick: corretto; Grazie. Sospetto che questo sarà più veloce della tua versione, dal momento che 'contains' chiama un metodo nativo (vedi l'origine jQuery). Sono troppo pigro per controllare. – SLaks

+0

@SLaks - * Se * il browser lo supporta sì, anche se non è possibile utilizzare un selettore direttamente qui in modo che sia un po 'disordinato, dipende da ciò che si sta facendo (in un ciclo o meno). Solo un pensiero: sarebbe bello qui se '.closest()' ha preso un set di elementi per filtrare come va ... –

5

È possibile combinare .parents() con .filter(), in questo modo:

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

questo diventa tutti genitori condivisi, è possibile prendere la .first() o .last() ... qualunque cosa di cui avevamo bisogno.

You can test it here. Nota questo è molto più veloce di .has() dato che stiamo confrontando solo 2 set di elementi DOM, non confrontandoli in modo ricorsivo. Inoltre, il set risultante sarà nell'ordine che sale il documento, in questo esempio <p> quindi <body>.

+1

Molto meglio camminare sull'albero fino alla radice e cercare di trovare la prima corrispondenza rispetto a una ricerca completa in ogni sottostruttura. – Gumbo

0

non jQuery versione:

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

Ecco una soluzione molto semplice non 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

Problemi correlati