2012-01-17 15 views
9

¿Existe un medio para detectar si un elemento aparece antes o después de otro elemento en el marcado? Esto es independientemente de posición en DOM. Podría ser un niño, un hermano, un padre o uno de los padres. Esta es una pregunta general, por lo que no hay margen de beneficio para compartir.Es elemento antes o después de otro elemento en DOM

Para aclarar: esto se refiere a la posición del elemento en el marcado, no a su posición de visualización. Ahora que lo pienso, mi pregunta es un poco extraña porque si tienes el elemento X y el elemento Y, entonces puedes tener estos escenarios.

//in regards to y 
<x /> 
<y /> //:after 

<y /> //:before 
<x /> 

<x><y /></x> //not really before or after is it? 
+0

ubicación en el marcado = ubicación en DOM –

+0

¿Qué quiere decir después? ¿Quiere decir después de la forma en que lo leería un lector del idioma de esa página? ¿Tan inferior en la página O a la misma altura y a la derecha para un lector en inglés? –

+0

@MikeSamuel - Quiero decir, como si realmente imprimiera el marcado. Supongo que habría tres estados posibles. antes, después o hijo de (ninguno) – mrtsherman

Respuesta

5

Sí, tipo de. DOM3 introdujo Node.compareDocumentPosition, que le permite comparar la posición de dos elementos. La funcionalidad no es muy amigable: se trata de máscaras de bits: se trata de un complemento jQuery que debería simplificar su uso.

Este código solo se prueba en Firefox 9 y en la versión actual de Chromium. Ciertamente no funcionará en versiones anteriores de IE.

$.fn.docPosition = function(element) { 
    if (element.jquery) element = element[0]; 

    var position = this[0].compareDocumentPosition(element); 

    if (position & 0x04) return 'after'; 
    if (position & 0x02) return 'before'; 
}; 

Además, un elemento que contiene a otro se considera que está antes en la estructura.


bien, un poco googlear me da this blog post by John Resig (el creador de jQuery), que incluye compatibilidad con IE < 9. (Es un poco feo: utiliza dos bits no estándar de funcionalidad: contains y sourceIndex.) Este código debe ser transversal navegador:

$.fn.docPosition = function (element) { 
    function comparePosition(a, b) { 
     return a.compareDocumentPosition ? 
      a.compareDocumentPosition(b) : 
      a.contains ? 
      (a != b && a.contains(b) && 16) + 
       (a != b && b.contains(a) && 8) + 
       (a.sourceIndex >= 0 && b.sourceIndex >= 0 ? 
       (a.sourceIndex < b.sourceIndex && 4) + 
        (a.sourceIndex > b.sourceIndex && 2) : 
       1) 
      + 0 : 0; 
    } 

    if (element.jquery) element = element[0]; 

    var position = comparePosition(this[0], element); 

    if (position & 0x04) return 'after'; 
    if (position & 0x02) return 'before'; 
}; 
+0

En lugar de trabajar con máscaras de bits, puede hacer referencia a las diversas constantes involucradas, como Nodo.DOCUMENT_POSITION_PRECEDING. Consulte https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition – user393274

1

no tengo código completo, pero el enfoque tomaría (si Node.compareDocumentPosition no está disponible) es:

  1. obtener la cadena de ambos elementos .parents()
  2. encontrar el elemento más adelante en cada cadena que está en ambas cadenas: esta es la matriz común
  3. luego verifique el siguiente elemento de cada cadena, si su índice es anterior o posterior al

hay trucos que puede utilizar para hacer (1) y (2) más simples por tener el DOM hacer algo del trabajo por usted:

var $a = $('#a'); // first element 
var $b = $('#b'); // first element 

$a.parents().andSelf().addClass('search'); // mark A and all of A's ancestors 
var $parent = $b.closest('.search');  // find B's first marked ancestor 
+0

Me gusta mucho esto. Gracias por la idea creativa. Voy a perder el tiempo con esto esta noche. – mrtsherman

2

Un método de fuerza bruta puede ser conseguir todos los elementos, luego obtenga el índice de cada elemento dentro del conjunto.

var all = $('*'); 

var a_index = all.index($('#element_a')); 
var b_index = all.index($('#element_b')); 

if(a_index < b_index) 
    alert('a is first'); 
else 
    alert('b is first'); 

Para una solución compatible con el navegador no jQuery, usted puede hacer esto:

function sortInDocumentOrder(a, b) { 
    var all = document.getElementsByTagName('*'); 

    for(var i = 0; i < all.length; ++i) { 
     if(all[i] === a) 
      return [a,b]; 
     else if(all[i] === b) 
      return [b,a]; 
    } 
} 

doy dos elementos, y les volverá en el orden del documento.

var a = document.getElementById('a'); 
var b = document.getElementById('b'); 

var inOrder = sortInDocumentOrder(a, b); 
+0

Inteligente. Voy a perder el tiempo con esto. Hice la pregunta por capricho, así que me tomará un poco de tiempo probar los casos de uso y asegurarme de que sea una respuesta adecuada. – mrtsherman

+0

Alrighty. Déjeme saber si usted tiene preguntas. –

7

node.compareDocumentPosition

Resumen
compara la posición del nodo actual en contra de otro nodo en cualquier otro documento.

ACTUALIZACIÓN: Esto no funciona en todos los navegadores, pero no es una solución para eso. Gracias por Alnitak (ver comentarios de respuesta) por proporcionar el enlace: cross browser compare document position

+0

Tenga en cuenta que esto no es compatible con IE <9. Sin embargo, estoy seguro de que hay cuñas disponibles. –

+0

hay un shim de navegador cruzado para 'node.compareDocumentPosition' escrito por @Raynos en http://stackoverflow.com/a/8334758/6782 – Alnitak

+0

@amnotiam agregó – amosrivera

1

Estás confundiendo algunas cosas. La ubicación en el marcado es la ubicación en el DOM. Esta línea muestra su confusión:

<x><y /></x> //not really before or after is it? 

Por supuesto y es despuésx por cualquier definición razonable. Debería pensar en el DOM como un árbol, no como caracteres en un archivo de texto.

Ahora, como para determinar la posición, utilice Node.compareDocumentPosition:

node.compareDocumentPosition(otherNode) 

El valor de retorno es una máscara de bits con los siguientes valores:

DOCUMENT_POSITION_DISCONNECTED = 0x01; 
DOCUMENT_POSITION_PRECEDING = 0x02; 
DOCUMENT_POSITION_FOLLOWING = 0x04; 
DOCUMENT_POSITION_CONTAINS = 0x08; 
DOCUMENT_POSITION_CONTAINED_BY = 0x16; 
+0

Si pensamos en el DOM como un árbol, entonces' y' podría aparece antes de 'x' si tuviéramos que usar un recorrido en orden o posterior al pedido. Solo depende del método transversal que los implementadores de la especificación elijan utilizar. – Anurag

0

esta pregunta requiere un conjunto de reglas sobre lo que se considera antes de y después de. Ciertamente es fácil recorrer los elementos en body y ver qué viene después, pero ¿hay algún tipo de precedencia jerárquica? ¿Qué hay de repetir elementos?

<foo> 
    <bar> 
     <foobar /> 
    </bar> 
</foo> 
<foo> 
    <baz /> 
</foo> 
<foobar /> 

¿Se baz vienen antes foobar?

Crearía dos funciones isBefore y isAfter; en este caso, ambos serían ciertos (haciendo una primera búsqueda en profundidad).


var el = $('*'); 

function isBefore(elA, elB){ 
    return (el.index($(elA).first()) < el.index($(elB).last())); 
} 

function isAfter(elA, elB){ 
    return (el.index($(elA).last()) > el.index($(elB).first())); 
} 


isBefore('body', 'head'); // false 
isAfter('body', 'head'); // true 
Cuestiones relacionadas