2009-08-17 17 views
7

Jeśli mam dwa węzły w dokumencie HTML, jak mogę określić, który z nich jest pierwszy w kolejności dokumentów HTML w JavaScript przy użyciu metod DOM?Ustalanie kolejności dokumentów z węzłów

Na przykład

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

Odpowiedz

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

Należy zauważyć, że metoda Resig działa tylko na węzłach elementów, a nie na węzłach tekstowych. – Michael

+0

Tak. Węzły tekstowe nie mają .sourceIndex i nie mają .contains(). – Michael

+0

&& nie robi nic we wszystkich tych przypadkach, ponieważ RHS jest zawsze prawdziwe. – gsnedders

1

raczej trudne, ja osobiście itterate się każde drzewo, póki nie znaleźli wspólny ansester, a następnie sprawdzić, który węzeł nadrzędny (lub rzeczywisty węzeł Jeśli tak niski) pochodzi pierwsza zaczynając firstChild i działa poprzez rodzeństwa, coś jak:

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

i nie wystarczy zmienić ten kod, starając się naprawić dwa możliwe problemy, nie testowałem tego nowego zmienił jednak, więc jeśli przerwy coś będę musiał spróbować ponownie . (Edytowany ponownie, aby naprawić błąd stylu "nawet nie działa").

+0

Nicea odpowiedź, ale myślę, że to się nie powiedzie, jeśli jeden węzeł jest przodkiem drugiego. Musisz przetestować, czy "i" przekracza długość którejkolwiek z tablic. – Alohci

+0

To bardzo ciekawy pomysł, znacznie bardziej wydajny niż ten, o którym myślałem. Zamierzam uwzględnić to jako powrót, jeśli a.compareDocumentPosition nie jest zdefiniowany (jest to metoda DOM 3). Dzięki! – Michael

4

Można użyć funkcji DOM compareDocumentPosition który powróci różne numery oparte na związkach dwoma węzłami:

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

Potencjalnie wynik może być sumą więcej niż jednego z tych kodów, odpowiedź brzmi bitmask, ale nie mogę sobie wyobrazić sytuacji, w której dwa z tych warunków byłyby prawdziwe w tym samym czasie. Należy również pamiętać, że „odłączony” Wynik zostaną zwrócone, na przykład z węzłów, które zostały utworzone, ale nie dodał do drzewa dokumentu jeszcze

+0

Należy zauważyć, że * compareDocumentPosition * nie jest obsługiwana przez żadną wersję Internet Explorera, włącznie z IE 8. – NickFitz

+0

Myślę, że pełnym rozwiązaniem będzie powrót do kodu scragara, jeśli nie jest zdefiniowany. Dzięki za wskazówkę. – Michael

Powiązane problemy