2010-11-04 9 views
9

Digamos que tengo esta estructura DOMEncontrar el primer padre compartida de los dos elementos

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

Usando jQuery Quiero llegar a conocer el primer padre compartida del

<b>are</b> 

y la

<tt>you</tt> 

De abajo hacia arriba, esta sería la etiqueta < p> no < body>.

¿Alguna idea sobre cómo determinar el primer elemento principal compartido que utiliza jQuery?

+0

más reciente ancestro común. ¡Siento que estoy estudiando genética o algo así! – jball

Respuesta

9

De esta manera:

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

Si b es un selector (en oposición a un elemento DOM), se puede cambiar a:

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

Esto es más corto, pero sustancialmente más lento.

El orden de a y b es irrelevante; si b está más cerca de la matriz, será más rápido.

+0

Esto no funcionará, puedes probarlo aquí: http://www.jsfiddle.net/nick_craver/a7hgu/ tienes que 'regresar' en una función' .filter() 'para obtener resultados. –

+0

@Nick: Solucionado; Gracias. Sospecho que esto será más rápido que su versión, ya que 'contains' llama a un método nativo (consulte la fuente de jQuery). Soy demasiado flojo para mirar. – SLaks

+0

@SLaks - * Si * el navegador lo admite sí, aunque no puede usar un selector directamente aquí, por lo que es un poco más complicado, depende de lo que esté haciendo con él (en un bucle o no). Solo un pensamiento: sería bueno si '.closest()' tomara un conjunto de elementos para filtrar a medida que avanza ... –

5

Se pueden combinar con .parents().filter(), así:

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

esto se pone todos los padres compartidas, a continuación, puede tomar la .first() o .last() ... lo que se necesita.

You can test it here. Tenga en cuenta que esto es mucho más rápido que .has() ya que solo estamos comparando 2 conjuntos de elementos DOM, no comparando recursivamente muchos. Además, el conjunto resultante estará en el orden que sube el documento, en este ejemplo <p> y luego <body>.

+1

Mucho mejor para recorrer el árbol hasta la raíz e intentar encontrar la primera coincidencia que hacer una búsqueda completa en cada subárbol. – Gumbo

0

:

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

Aquí es una solución no jQuery muy simple:

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

Cuestiones relacionadas