2009-08-17 12 views
7

Wenn ich zwei Knoten in einem HTML-Dokument habe, wie kann ich feststellen, welche in HTML-Dokumentenreihenfolge in Javascript mit DOM-Methoden zuerst kommt?Ermitteln der Dokumentenreihenfolge von Knoten

Zum Beispiel

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

Antwort

5

Resig to the rescue hinzugefügt:

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

Es sollte beachtet werden, dass die Methode von Resig nur auf Elementknoten funktioniert, nicht auf Textknoten. – Michael

+0

Ja. Textknoten haben keinen .sourceIndex und sie haben .contains() nicht. – Michael

+0

&& tut nichts in all diesen Fällen, weil die RHS immer wahr ist. – gsnedders

1

Ziemlich schwierig, ich persönlich würde jeden Baum itterate, bis ich eine gemeinsame ansester gefunden, dann prüfen Sie, welche übergeordneten Knoten (oder die aktuellen Knoten, wenn dieser niedrig) kommt beginnend zuerst mit first und durch Geschwister arbeiten, so etwas wie:

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

ich habe nur diesen Code bearbeiten in einem Versuch, zwei mögliche Probleme zu beheben, ich habe nicht diese neue bearbeiten jedoch getestet, so dass, wenn etwas kaputt geht werde ich wieder versuchen müssen . (Erneut bearbeitet, um einen "does not even run" Stil-Bug zu beheben).

+0

Nizza Antwort, aber ich denke, das schlägt fehl, wenn ein Knoten ist der Vorfahre des anderen. Sie müssen testen, ob "i" über die Länge eines der Arrays hinausgeht. – Alohci

+0

Es ist eine sehr interessante Idee, viel effizienter als die, an die ich gedacht hatte. Ich werde es als Fallback einschließen, wenn a.compareDocumentPosition nicht definiert ist (es ist eine DOM 3-Methode). Danke! – Michael

4

können Sie die DOM-Funktion compareDocumentPosition verwenden, die unterschiedliche Zahlen zurückkehren wird basierend auf Beziehungen der beiden Knoten:

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

Potentiell könnte das Ergebnis die Summe von mehr als einer dieser Codes werden als Die Antwort ist eine Bitmaske, aber ich kann mir keine Situation vorstellen, in der zwei dieser Bedingungen zur gleichen Zeit wahr wären. Beachten Sie auch, dass das „getrennt“ Ergebnis zum Beispiel mit Knoten zurückgegeben werden würde, die erstellt wurden, aber nicht auf den Dokumentenbaum noch

+0

Beachten Sie, dass * compareDocumentPosition * von keiner Version von Internet Explorer bis einschließlich IE 8 unterstützt wird. – NickFitz

+0

Ich denke, die vollständige Lösung wird darin bestehen, auf den Scragar-Code zurückzugreifen, wenn er nicht definiert ist. Danke für den Tipp. – Michael