2012-01-17 109 views
9

是否有一种检测元素是出现在标记中的另一个元素之前还是之后的方法?这是,不管在DOM中的位置。它可能是小孩,兄弟姐妹,父母或父母的父母。这是一个普遍的问题,所以没有共享的标记。DOM中的另一个元素之前还是之后的元素

澄清 - 这是关于元素在标记中的位置,而不是其显示位置。现在我想到了我的问题有点奇怪,因为如果你有元素X和元素Y,那么你可以有这些场景。

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

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

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

位置=在DOM – 2012-01-17 22:00:00

+0

位置是什么意思后?你的意思是说,在那个页面的语言的读者将扫描它的方式?所以在页面上或者在同一高度下,在英文阅读器的右边? – 2012-01-17 22:01:44

+0

@MikeSamuel - 我的意思是,如果你真的打印出标记。我想可能会有三种状态。 (既) – mrtsherman 2012-01-17 22:02:41

回答

5

是的,有点。 DOM3介绍Node.compareDocumentPosition,它可以让你比较两个元素的位置。功能不是很友好:它涉及位掩码:这是一个jQuery插件,应该简化它的使用。

此代码仅在Firefox 9和当前版本的Chromium上进行测试。当然,它不适用于旧版本的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'; 
}; 

此外,包含另一个被认为是前它在结构的元件。


行,一个小谷歌搜索给我this blog post by John Resig(jQuery的创建者),其中包括与IE < 9.兼容性(这是一个小丑陋:它使用的功能的两个非标准位:containssourceIndex。)该代码应该是跨浏览器:

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

而不是使用位掩码,您可以引用涉及的各种常量,例如Node.DOCUMENT_POSITION_PRECEDING。请参阅https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition – user393274 2016-10-07 16:30:41

1

我没有完整的代码,但是这种方法我会采取(如果Node.compareDocumentPosition不可用)是:

  1. 获得.parents()链中的元素
  2. 找到元素在两条链中最长的每条链 - 这是常见的父代
  3. 然后检查每个链下的下一个元素,无论它的索引是在其他之前还是之后

有技巧,你可以用它来制作(1)和(2)简单的通过具有DOM做一些对你的工作:

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

我非常喜欢这个。感谢你的创意。今晚我会讨论这个。 – mrtsherman 2012-01-17 22:22:16

2

蛮力方法可能是让所有的元素,然后获取集合中每个元素的索引。

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'); 

对于浏览器兼容的非jQuery的解决方案,你可以这样做:

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]; 
    } 
} 

给它两个元素,它会在文档顺序返回。

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

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

聪明。我将要解决这个问题。我突发奇想地问了这个问题,所以我会花一些时间来测试用例,并确定这是一个合适的答案。 – mrtsherman 2012-01-17 22:21:18

+0

好吧。如果您有任何问题,请告诉我。 – 2012-01-17 22:24:02

7

node.compareDocumentPosition

摘要
比较针对任何其他文件中的另一节点的当前节点的位置。

UPDATE: 这并不在所有的浏览器,但有一个修复了点。感谢Alnitak提供的链接(见答案评论):cross browser compare document position

+0

请记住,这在IE <9中不受支持。我确信有垫片可用。 – 2012-01-17 22:13:21

+0

有一个针对'node.compareDocumentPosition'的跨浏览器shim,由@Raynos撰写,地址为http://stackoverflow.com/a/8334758/6782 – Alnitak 2012-01-17 22:41:03

+0

@amnotiam added – amosrivera 2012-01-18 06:51:18

1

你混淆了一些事情。标记中的位置是 DOM中的位置。这条线显示你的困惑:

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

当然y的是x任何合理的解释。您应该将DOM看作树,而不是文本文件中的字符。现在

,作为确定的位置,使用Node.compareDocumentPosition

node.compareDocumentPosition(otherNode) 

返回值是具有以下值的掩码:

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

如果我们将DOM看作一棵树,那么'y'可以如果我们要使用按顺序或后序遍历,就会出现在'x'之前。它仅取决于规范实现者选择使用哪种遍历方法。 – Anurag 2012-01-17 22:28:03

0

这个问题,需要在什么被认为是一组规则之前之后。遍历body中的元素并且看看接下来会发生什么,这当然很容易,但是是否存在任何分层优先级?重复元素呢?

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

请问baz是否在foobar之前?

我会创建两个函数isBeforeisAfter;在这种情况下,它们都是真实的(首先进行深度查找)。在标记


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 
相关问题