2012-01-17 108 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 
相關問題