Imagine some DOM elements:
<ul id="list">
<li data-index="3">Baz</li>
<li data-index="1">Foo</li>
<li data-index="2">Bar</li>
</ul>
How can these elements be sorted using JavaScript and without jQuery?
Something similar to:
document.getElementById('list').sort(function(li) { return li.dataset.index; });
Imagine some DOM elements:
<ul id="list">
<li data-index="3">Baz</li>
<li data-index="1">Foo</li>
<li data-index="2">Bar</li>
</ul>
How can these elements be sorted using JavaScript and without jQuery?
Something similar to:
document.getElementById('list').sort(function(li) { return li.dataset.index; });
Share
Improve this question
asked Jun 21, 2014 at 13:52
Drew NoakesDrew Noakes
311k170 gold badges697 silver badges765 bronze badges
14
- Try searching for this question online and you'll find nothing out there that covers this other than some jQuery stuff. Seems like a perfectly reasonable question to me. Explain why if you feel otherwise. – Drew Noakes Commented Jun 21, 2014 at 13:58
-
1
Put references to
li
elements into an array (or convert NodeList into one), sort, and insert elements back into DOM in array order … done. – C3roe Commented Jun 21, 2014 at 14:00 - @CBroe, that involves a lot of DOM churn, which is bad for performance especially if the list is already mostly sorted. I'd like to do the sort in-place ideally. – Drew Noakes Commented Jun 21, 2014 at 14:01
- 1 "In-place" sorting would probably be even slower, you'd need to append the same element several times. Btw. I didn't vote down, but maybe the lack of a true attempt to solve this has caused a down-vote. – Teemu Commented Jun 21, 2014 at 14:04
- 2 jsfiddle/f4s7s/1 – C3roe Commented Jun 21, 2014 at 14:12
3 Answers
Reset to default 5You should use the ordering capabilities of flexboxes. This will allow to re-order the elements without moving them around in the DOM. This involves setting the CSS order
property.
See https://developer.mozilla/en-US/docs/Web/Guide/CSS/Flexible_boxes for more details.
Some time ago I wrote this:
function sortChildren(wrap, f, isNum) {
var l = wrap.children.length,
arr = new Array(l);
for(var i=0; i<l; ++i)
arr[i] = [f(wrap.children[i]), wrap.children[i]];
arr.sort(isNum
? function(a,b){ return a[0]-b[0]; }
: function(a,b){ return a[0]<b[0] ? -1 : a[0]>b[0] ? 1 : 0; }
);
var par = wrap.parentNode,
ref = wrap.nextSibling;
par.removeChild(wrap);
for(var i=0; i<l; ++i) wrap.appendChild(arr[i][1]);
par.insertBefore(wrap, ref);
}
Basically:
First create an array to store the elements with its corresponding value returned by the parator function.
We could also run the function when sorting, but since DOM interactions are slow, this way we make sure the function will only run once per element.
Then, we sort it using native
sort
.If
isNum
argument is truly, we use a sorting function that pares numerically. This is needed if the parator function returns strings but you want to pare numerically instead of lexicographically.Now, we remove the wrapper element from the DOM. This way reordering the children will be less expensive (e.g. avoiding repaitings).
Finally we reorder the children, and insert wrapper back in its place.
Run it like
sortChildren(
document.getElementById('list'),
function(li) { return li.dataset.index; },
true
);
or
sortChildren(
document.getElementById('list'),
function(li) { return +li.dataset.index; }
);
Demo
<!doctype html>
<html lang="en">
<head>
<meta charset= "utf-8">
<title>sort list</title>
</head>
<body>
<strong>Double click the list to sort by data-index</strong>
<ul id= "list">
<li data-index= "3">Baz</li>
<li data-index= "1">Foo</li>
<li data-index= "2">Bar</li>
</ul>
<script>
document.body.ondblclick=function(){
var A=[], pa= document.getElementById('list');
var itemz= pa.getElementsByTagName('li');
A.slice.call(itemz).sort(function(a, b){
return a.getAttribute('data-index')-b.getAttribute('data-index');
}).forEach(function(next){
pa.appendChild(next);
});
}
</script>
</body>
</html>
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1741484325a4349528.html
评论列表(0条)