Si j'ai une liste comme celle-ci:
<ul id="mylist">
<li id="list-item1">text 1</li>
<li id="list-item2">text 2</li>
<li id="list-item3">text 3</li>
<li id="list-item4">text 4</li>
</ul>
Quelle est la façon la plus simple de réorganiser les nœuds DOM à ma préférence? (Cela doit se produire automatiquement lorsque la page se charge, la préférence d'ordre de liste est obtenue à partir d'un cookie)
Par exemple.
<ul id="mylist">
<li id="list-item3">text 3</li>
<li id="list-item4">text 4</li>
<li id="list-item2">text 2</li>
<li id="list-item1">text 1</li>
</ul>
Bien qu'il existe probablement un moyen plus facile de le faire à l'aide d'une bibliothèque JS, voici une solution de travail utilisant Vanilla js.
var list = document.getElementById('mylist');
var items = list.childNodes;
var itemsArr = [];
for (var i in items) {
if (items[i].nodeType == 1) { // get rid of the whitespace text nodes
itemsArr.Push(items[i]);
}
}
itemsArr.sort(function(a, b) {
return a.innerHTML == b.innerHTML
? 0
: (a.innerHTML > b.innerHTML ? 1 : -1);
});
for (i = 0; i < itemsArr.length; ++i) {
list.appendChild(itemsArr[i]);
}
Vous pourriez trouver que le tri des nœuds DOM ne fonctionne pas bien. Une approche différente serait d'avoir dans votre javascript un tableau qui représente les données qui iraient dans les nœuds DOM, trier ces données, puis régénérer le div qui contient les nœuds DOM.
Peut-être que vous n'avez pas autant de nœuds à trier, donc cela n'aurait pas d'importance. Mon expérience est basée sur la tentative de trier des tableaux HTML en manipulant le DOM, y compris des tableaux avec des centaines de lignes et quelques dizaines de colonnes.
Voyez-le en action: http://jsfiddle.net/stefek99/y7JyT/
jQuery.fn.sortDomElements = (function() {
return function(comparator) {
return Array.prototype.sort.call(this, comparator).each(function(i) {
this.parentNode.appendChild(this);
});
};
})();
Terse
Utilisez la syntaxe es6 pour recourir aux enfants:
var list = document.querySelector('#test-list')
[...list.children]
.sort((a,b)=>a.innerText>b.innerText?1:-1)
.map(node=>list.appendChild(node))
Ma version, l'espoir sera utile pour les autres:
var p = document.getElementById('mylist');
Array.prototype.slice.call(p.children)
.map(function (x) { return p.removeChild(x); })
.sort(function (x, y) { return /* your sort logic, compare x and y here */; })
.forEach(function (x) { p.appendChild(x); });
Si vous utilisez déjà jQuery, je recommanderais tinysort: http://tinysort.sjeiti.com/
$("li").tsort({order:"asc"});
$("li").tsort({order:"desc"});
Voici une fonction ES6 pour trier les nœuds DOM en place:
const sortChildren = ({ container, childSelector, getScore }) => {
const items = [...container.querySelectorAll(childSelector)];
items
.sort((a, b) => getScore(b) - getScore(a))
.forEach(item => container.appendChild(item));
};
Voici comment l'utiliser pour trier avis d'utilisateurs inexploités par score :
sortChildren({
container: document.querySelector("#main-stream"),
childSelector: ".item",
getScore: item => {
const rating = item.querySelector(".rating");
if (!rating) return 0;
const scoreString = [...rating.classList].find(c => /r\d+/.test(c));
const score = parseInt(scoreString.slice(1));
return score;
}
});
sans trop analyser si cela apporte quelque chose de nouveau à la table, j'utilise généralement ceci:
function forEach(ar, func){ if(ar){for(var i=ar.length; i--; ){ func(ar[i], i); }} }
function removeElement(node){ return node.parentNode.removeChild(node); }
function insertBefore(ref){ return function(node){ return ref.parentNode.insertBefore(node, ref); }; }
function sort(items, greater){
var marker = insertBefore(items[0])(document.createElement("div")); //in case there is stuff before/after the sortees
forEach(items, removeElement);
items.sort(greater);
items.reverse(); //because the last will be first when reappending
forEach(items, insertBefore(marker));
removeElement(marker);
}
où item est un tableau d'enfants du même parent. nous supprimons en commençant par le dernier et ajoutons en commençant par le premier pour éviter le scintillement dans la partie supérieure qui est probablement à l'écran. j'obtiens généralement mon tableau d'articles comme ceci:
forEachSnapshot(document.evaluate(..., 6, null), function(n, i){ items[i] = n; });