2009-08-17 6 views
7

Si j'ai deux noeuds dans un document HTML, comment puis-je savoir lequel vient en premier dans l'ordre des documents HTML en Javascript en utilisant les méthodes DOM?Détermination de l'ordre des documents à partir des noeuds

Par exemple,

function funstuff(a, b) { 
    //a and b can be any node in the DOM (text, element, etc) 
    if(b comes before a in document order) { 
     var t = b; b = a; a = t; 
    } 
    // process the nodes between a and b. I can handle this part 
    // when I know that a comes before b. 
} 

Répondre

5

Resig to the rescue:

// Compare Position - MIT Licensed, John Resig 
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; 
} 
+0

Il convient de noter que la méthode Resig ne fonctionne que sur les nœuds d'éléments, pas sur les nœuds de texte. – Michael

+0

Ouais. Les nœuds de texte n'ont pas .sourceIndex et ils n'ont pas de .contains(). & – Michael

+0

&& ne fait rien dans tous ces cas, parce que le RHS est toujours vrai. – gsnedders

1

plutôt difficile, personnellement, j'itterate jusqu'à chaque arbre jusqu'à ce que je trouve un ansester commun, puis vérifier quel nœud parent (ou le nœud réel si ce faible) apparaît en premier en commençant par firstChild et de travailler à travers les frères et sœurs, quelque chose comme:

function OrderCheck(node1, node2){ 

    var ar1 = [null, node1]; 
    var ar2 = [null, node2]; 

    for(var i = 1; ar1[i] != null; i++) 
     ar1[i+1]=ar1[i].parentNode; 
    for(var i = 1; ar2[i] != null; i++) 
     ar2[i+1]=ar2[i].parentNode; 
    ar1.reverse(); ar2.reverse(); // easier to work with. 
    i = 0; 
    while(ar1[i] === ar2[i]){ 
     if(ar1[i] === null) 
     return 0; 
     else 
     i++ 
    } 

    if(ar1[i] === null) 
     return 2; 
    if(ar2[i] === null) 
     return 1; 

    if(i != 0){ 
     var n = ar1[i-1].firstChild; 
     do{ 
     if(n === ar1[i]) 
      return 1; 
     if(n === ar2[i]) 
      return 2; 
     }while(n = n.nextSibling); 
    } 
     return -1;// Shouldn't happen. 
    } 

    var order = OrderCheck(document.body, document.body.previousSibling); 
    if(order == 1){ 
     // element 1 first 
    }else if(order == 2){ 
     // element 2 first 
    }else{ 
     // there was an error. 
    } 

Je ne vient modifier ce code pour tenter de résoudre deux problèmes possibles, je ne l'ai pas testé cette nouvelle édition cependant, si quelque chose se brise, je vais devoir essayer de nouveau . (Edité à nouveau pour corriger un bug de style "ne fonctionne même pas").

+0

Belle réponse, mais je pense que cela échoue si un noeud est l'ancêtre de l'autre. Vous devez tester pour 'je' aller au-delà de la longueur de l'un des tableaux. – Alohci

+0

C'est une idée très intéressante, beaucoup plus efficace que celle à laquelle j'avais pensé. Je vais l'inclure comme repli si un.compareDocumentPosition n'est pas défini (c'est une méthode DOM 3). Merci! – Michael

4

Vous pouvez utiliser la fonction DOM compareDocumentPosition qui renvoie des numéros différents en fonction des relations entre les deux nœuds:

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

potentiellement le résultat pourrait être la somme de plus d'un de ces codes comme la réponse est un masque de bits, mais je ne peux pas imaginer une situation où deux de ces conditions seraient vraies en même temps. A noter également que le résultat « déconnecté » serait renvoyé par exemple avec des noeuds qui ont été créés, mais pas ajouté à l'arbre du document encore

+0

Notez que * compareDocumentPosition * n'est supporté par aucune version d'Internet Explorer, y compris IE 8. – NickFitz

+0

Je pense que la solution complète sera de revenir au code de scragar s'il n'est pas défini. Merci pour le conseil. – Michael

Questions connexes