根据DOM元素在DOM中的位置对包含DOM元素的数组进行排序
Sort array containing DOM elements according to their position in the DOM
上下文
我已经构建了一个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索引"。
你能想到什么方法?(如果编写代码,欢迎使用vanillaJS和jQuery。(
有一个非常有用的函数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;
});
虽然我不建议您采用这种方法,但使用jquery可以获得"全局DOM索引":
var $all = $("*");
// use index to get your element's index within the entire DOM
$all.index($YOUR_EL);
您不必进行大量重构就可以利用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,但它能完成任务。实际示例
这样做的优点是,它适用于jQuery支持的所有浏览器,而不必自己处理边缘情况(例如,IE8不支持compareDocumentPosition
(。
如果您可以假设页面上的可见位置是相同的,那么这可能是一个相对快速的解决方案:
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。
- 如何在DOM元素上按类型构建此函数
- DOM元素和angular元素之间的主要区别是什么
- 当带有渲染器的DOM元素不在屏幕顶部时,移动了场景的坐标
- 使用jquery创建dom元素会导致ie9出现拒绝访问错误
- 如何在使用Ractive.extend()时引用DOM元素
- 在d3中向DOM元素添加了图像,但现在它赢得了't过渡
- 如何'剪切'DOM元素并将其显示在其他位置
- 转换<a>使用jQuery将文本字符串转换为dom元素
- d3在数据更新时错误地附加了dom元素
- 访问VueJS中的DOM元素
- 在Meteor中如何查找DOM元素(渲染后)
- IE9-添加和删除DOM元素会破坏父keydown事件
- 未捕获错误:元素缓存中id为x的DOM元素与DOM中的元素不同
- 在 ng-if 编译后访问指令中的 DOM 元素
- spin.js/angular spinner:如何将spin定位到DOM元素中(包括plunker演示)
- 如何在dom元素中插入输入标记数据插件
- Mobile Safari、jQuery以及绑定到未来的DOM元素
- 从字符串创建dom元素时添加多个类
- 如何根据客户端的屏幕大小使用javascript更改DOM元素
- 为onClick-hander插入临时DOM元素