2009-08-17 33 views
7

如果我在HTML文档中有两个节点,那么如何判断使用DOM方法的Javascript文档中,哪一个以HTML文档顺序排在第一位?确定来自节点的文档顺序

例如,

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

回答

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

应该指出,Resig的方法只能在元素节点上工作,而不能在文本节点上工作。 – Michael 2009-09-16 19:33:29

+0

是的。文本节点没有.sourceIndex,并且没有.contains()。 – Michael 2009-09-17 18:35:54

+0

&&在所有这些情况下都不会做任何事情,因为RHS总是如此。 – gsnedders 2011-04-12 11:43:41

1

相当困难,我个人itterate高达每个树,直到我发现一个共同的ansester,然后检查该父节点(或者如果该低实际节点)是一第一开始则firstChild并通过兄弟姐妹的工作,是这样的:

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

我只是在尝试解决两个可能的问题,编辑该代码,我没有测试这种新的编辑但是,如果东西坏了,我得再次尝试。 (再次修改以修复“不会运行”的风格错误)。

+0

尼斯的答案,但我认为,如果一个节点失败是另一个的祖先。你需要测试'i'超出任何一个数组的长度。 – Alohci 2009-08-17 23:52:21

+0

这是一个非常有趣的想法,比我想象的更有效率。如果没有定义a.compareDocumentPosition(这是一个DOM 3方法),我将把它作为回退来包含它。 谢谢! – Michael 2009-08-18 17:44:51

4

可以使用DOM功能compareDocumentPosition这将返回基于两个节点关系不同的数字:

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

潜在结果可能是这些代码作为一个以上的总和答案是一个掩码,但我无法想象这两种情况同时成立的情况。还要注意的是,“断开连接”的结果将返回例如与已创建的节点,但不会添加到文档树又

+0

请注意* compareDocumentPosition *不受任何版本的Internet Explorer支持,直到并包括IE 8。 – NickFitz 2009-08-18 09:32:13

+0

我认为完整的解决方案将回退到scragar的代码(如果未定义的话)。谢谢你的提示。 – Michael 2009-08-18 17:45:58