是DOM中另一个元素之前或之后的元素
Is element before or after another element in DOM
有没有一种方法可以检测一个元素是出现在标记中的另一个元素之前还是之后?这是,与DOM中的位置无关。它可以是孩子、兄弟姐妹、父母或父母的父母。这是一个一般性的问题,因此没有可共享的标记。
澄清一下——这是关于元素在标记中的位置,而不是它的显示位置。现在我想一想,我的问题有点奇怪,因为如果你有元素X和元素Y,那么你就可以有这些场景。
//in regards to y
<x />
<y /> //:after
<y /> //:before
<x />
<x><y /></x> //not really before or after is it?
是的,有点像。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';
};
此外,包含另一个元素的元素被认为在结构中位于它之前。
好吧,通过谷歌搜索,我看到了John Resig(jQuery的创建者)的这篇博客文章,其中包括与IE<9.(这有点难看:它使用了两个非标准的功能:contains
和sourceIndex
。)这段代码应该是跨浏览器的:
$.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';
};
node.compareDocumentPosition
摘要
将当前节点的位置与任何其他文档中的另一个节点的位置进行比较。
更新:这并不适用于所有浏览器,但有一个修复方法。感谢Alnitak提供的链接:跨浏览器比较文档位置
暴力方法可能是获取所有元素,然后获取集合中每个元素的索引。
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 );
您混淆了一些事情。标记中的位置是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;
我没有完整的代码,但我会采取的方法(如果Node.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
这个问题需要一组关于之前和之后的规则。遍历body
中的元素并查看下一步会发生什么当然很容易,但有任何层次优先权吗?重复元素呢?
<foo>
<bar>
<foobar />
</bar>
</foo>
<foo>
<baz />
</foo>
<foobar />
baz
在foobar
之前吗?
我将创建两个函数isBefore
和isAfter
;在这种情况下,它们都是真的(进行深度优先查找)。
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
以下是Node.compareDocumentPosition 的完整示例
/**
* 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;
}
了解元素是否出现在其他元素之前的简便方法:使用sourceIndex属性来检索对象的顺序位置。
function isBefore(a, b){
return a.sourceIndex < b.sourceIndex;
}
isBefore(head,body); //true
- 如何在一个元素动画之后延迟
- 单击其他元素或鼠标向上时隐藏输入框,但保留一次焦点
- 如何创建具有单个元素或元素数组的数组
- 如何使用 ContentTools 在之前或之后没有内容时保留多个
- 向下滚动时覆盖页面的第一个元素或块
- <noscript>标记单个元素或类似的东西
- 如何使用jQuery扩展方法为元素或类选择器创建自定义插件
- 显示隐藏的元素或更改链接元素上的行为
- 用于获取jQuery元素或值的方法
- jQuery没有'找不到元素或其属性
- 如何从HTML元素或Javascript变量中设置idoc变量值
- 如何将 HTML 元素或 DocumentFragment 附加到 DOM
- 由具有内联 JavaScript 的元素赋值的变量中的“this”对所有元素或已赋值的活动元素有效
- 字符、符号或数字之前或之后的空格;但是,不介于两者之间
- 在我的面板中创建我自己的侧边栏窗格,而不是在元素或源面板中
- 使用 Javascript 隐藏 html 中的元素或特定 ID
- 如何在 Backbone.js 中的点击事件中获取 jQuery 元素(或属性)
- 动态加载外部 JavaScript 并将其绑定到特定的 DOM 元素或命名空间
- 是DOM中另一个元素之前或之后的元素
- 在HTML元素之前或之后添加文本