我已经构建了一个jQuery插件,我正在以一种方式将DOM元素存储在一个数组中,主要是为了能够在这些元素旁边存储更多信息,而不必使用不那么多的东西。快data()
。
该数组看起来像:
[
{ element: DOMElement3, additionalData1: …, additionalData2: … },
{ element: DOMElement1, additionalData1: …, additionalData2: … },
{ element: DOMElement2, additionalData1: …, additionalData2: … },
]
此插件的工作方式阻止我以可预测的顺序将这些元素推送到数组,这意味着DOMElement3
实际上可以在低于DOMElement2
的索引处找到自己。
但是,我需要按照它们包含的DOM元素在DOM中出现的顺序排列这些数组元素。前面的示例数组一旦排序,将如下所示:
[
{ element: DOMElement1, additionalData1: …, additionalData2: … },
{ element: DOMElement2, additionalData1: …, additionalData2: … },
{ element: DOMElement3, additionalData1: …, additionalData2: … },
]
当然,如果DOMElement1
出现在DOM中的DOMElement2
之前,DOMElement2
出现在DOMElement3
之前。
jQuery add()
方法以与DOM中出现的顺序相同的顺序返回一组DOM元素。我可以使用它,但要求是我使用jQuery集合 - 这意味着我必须重构上述插件的大部分以使用不同的存储格式。这就是为什么我认为这是最后的解决方案。
我原本想象map()
和一种与每个DOM元素绑定的全局DOM索引都可以完成这个技巧,但似乎没有这样的“全局DOM索引”。
您能想到什么方法? (如果编写代码,欢迎使用vanilla JS和jQuery。)
答案 0 :(得分:13)
有一个非常有用的函数叫compareDocumentPosition
,它根据两个元素相对于彼此的位置返回一个数字。您可以在.sort
回调中使用此功能:
yourArray.sort(function(a,b) {
if( a === b) return 0;
if( !a.compareDocumentPosition) {
// support for IE8 and below
return a.sourceIndex - b.sourceIndex;
}
if( a.compareDocumentPosition(b) & 2) {
// b comes before a
return 1;
}
return -1;
});
答案 1 :(得分:1)
您不必进行大量重构以利用jQuery的排序。您可以将其用作临时排序机制。这是一个袖手旁观的事情:
function putInDocumentOrder(a) {
var elements;
// Get elements in order and remember the index of
// the entry in `a`
elements = $().add(a.map(function(entry, index){
entry.element.__index = index;
return entry.element;
}));
// Build array of entries in element order
a = elements.map(function(){
return a[this.__index];
}).get();
return a;
}
它需要一个expando,但它可以完成任务。 Live Example
这样做的好处是它适用于jQuery支持的所有浏览器,而不是你自己处理边缘情况(例如IE8不支持compareDocumentPosition
)。
答案 2 :(得分:1)
虽然我不建议你采用这种方法,但jquery可以获得“全局DOM索引”:
var $all = $("*");
// use index to get your element's index within the entire DOM
$all.index($YOUR_EL);
答案 3 :(得分:0)
如果您可以假设页面上的可见位置相同,那么这可能是一个相对快速的解决方案:
function compareByVisibleLocation(a, b) {
if (a.offsetTop > b.offsetTop) {
return 1;
} else if (a.offsetTop < b.offsetTop) {
return -1;
}
if (a.offsetLeft > b.offsetLeft) {
return 1;
} else if (a.offsetLeft < b.offsetLeft) {
return -1;
} else {
return 0;
}
}
nodes.sort(compareByVisibleLocation);
否则,您可以使用querySelectorAll()
快速构建索引(这是深度优先的预先遍序遍历),方法是使用indexed-node
类名明确标记要编制索引的节点。
var nodes = document.querySelectorAll('.indexed-node');
或者通过抓取所有单个节点类型,如果有效:
var nodes = document.querySelectorAll('div');
或者只是抓住所有节点:
var nodes = document.querySelectorAll('*');
然后为每个节点添加一个索引属性:
for (var i = 0; i < nodes.length; i++) { nodes[i].__DomIndex = i; }
您可以这样排序:
var nodes = yourGetMethod().sort(function(a,b) {
if (a === b) {
return 0;
} else if (a.__DomIndex > b.__DomIndex) {
return 1;
} else {
return -1;
}
});
应该适用于IE8。