Javascript 元素在DOM中的另一个元素之前还是之后

Javascript 元素在DOM中的另一个元素之前还是之后,javascript,jquery,Javascript,Jquery,是否有一种方法可以检测标记中某个元素是出现在另一个元素之前还是之后?这与DOM中的位置无关。它可以是孩子、兄弟姐妹、父母或父母的父母。这是一个一般性问题,因此没有可共享的标记 澄清-这与元素在标记中的位置有关,而不是其显示位置。现在我想起来了,我的问题有点奇怪,因为如果你有元素X和元素Y,那么你可以有这些场景 //in regards to y <x /> <y /> //:after <y /> //:before <x /> <x&g

是否有一种方法可以检测标记中某个元素是出现在另一个元素之前还是之后?这与DOM中的位置无关。它可以是孩子、兄弟姐妹、父母或父母的父母。这是一个一般性问题,因此没有可共享的标记

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

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

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

<x><y /></x> //not really before or after is it?
//关于y
//:之后
//:之前
//不是在之前或之后,是吗?

我没有完整的代码,但我将采取的方法(如果
节点.compareDocumentPosition
不可用)是:

  • 获取两个元素的
    .parents()
  • 找到两条链中每个链最远的元素-这是公共父级
  • 然后检查每个链下的下一个元素的索引是在另一个之前还是之后
  • 通过让DOM为您完成一些工作,您可以使用以下技巧简化(1)和(2):

    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
    

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

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

    是的,有点。引入了DOM3,它允许您比较两个元素的位置。功能不是很友好:它涉及位掩码:这是一个jQuery插件,应该可以简化它的使用

    此代码仅在Firefox9和当前版本的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';
    };
    
    此外,包含另一个元素的元素在结构中被视为在它之前


    好的,谷歌给了我(jQuery的创建者)一些信息,其中包括与IE的兼容性

    摘要
    将当前节点的位置与任何其他文档中的其他节点进行比较

    更新
    这并不适用于所有浏览器,但有一个解决方案。感谢Alnitak(请参阅答案评论)提供的链接:

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

    <x><y /></x> //not really before or after is it?
    
    返回值是具有以下值的位掩码:

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

    这个问题需要一套规则,规定在之前和之后考虑什么。遍历
    body
    中的元素并查看下一步是什么当然很容易,但是是否存在任何层次优先权?重复元素呢

    <foo>
       <bar>
           <foobar />
       </bar>
    </foo>
    <foo>
       <baz />
    </foo>
    <foobar />
    
    返回a.sourceIndex}以下是完整的示例


    标记中的位置=dom中的位置after是什么意思?你的意思是说,阅读该页面语言的读者会以何种方式扫描该页面?对于一个英语读者来说,是在页面的下方,还是在相同的高度和右边?@MikeSamuel-我的意思是,好像你真的打印出了标记。我想可能有三种状态。在第三个示例中,
    y
    通常被视为在
    x
    之后。DOM选择按文档顺序返回元素,因此
    x
    将被视为第一位。对于
    节点,有一个跨浏览器的垫片。请记住,IE<9不支持@Raynos编写的ComparedDocumentPosition
    。我确信有垫片可用。有一个跨浏览器垫片用于
    节点。ComparedDocumentPosition
    由@Raynos at cleer编写。我要把这件事搞砸了。我一时兴起问了这个问题,所以我需要一点时间来测试用例,并确保这是一个合适的答案。我非常喜欢这个。谢谢你的创意。今晚我将讨论这个问题。如果我们将DOM看作一棵树,那么如果我们使用顺序遍历或顺序后遍历,
    y
    可能会出现在
    x
    之前。这取决于规范实现者选择使用什么样的遍历方法。您不必使用位掩码,只需引用所涉及的各种常量,如Node.DOCUMENT\u POSITION\u。看,你能扩大你的答案吗?添加一些解释,显示这一行的位置。现在就像是评论“使用sourceIndex”
    <x><y /></x> //not really before or after is it?
    
    node.compareDocumentPosition(otherNode)
    
    DOCUMENT_POSITION_DISCONNECTED = 0x01;
    DOCUMENT_POSITION_PRECEDING = 0x02;
    DOCUMENT_POSITION_FOLLOWING = 0x04;
    DOCUMENT_POSITION_CONTAINS = 0x08;
    DOCUMENT_POSITION_CONTAINED_BY = 0x16;
    
    <foo>
       <bar>
           <foobar />
       </bar>
    </foo>
    <foo>
       <baz />
    </foo>
    <foobar />
    
    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
    
    function isBefore(a, b){
    
        /**
         * Checks if the node1 is before the node2 in the DOM tree
         * It is true if
         * + node1 is sibling before node2
         * + node1 contains node2
         * + node1 is in the subtree that is before node2 or the subtree that contains it
         */
        public isNodeBefore(node1: Node, node2: Node): boolean {
            // https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition
            return (node2.compareDocumentPosition(node1) & (Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINS)) != 0;
        }