web-dev-qa-db-fra.com

Le moyen le plus simple de trier les nœuds DOM?

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>
47
James

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]);
}
71
nickf

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.

16
Corey Trager

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

13
Mars Robertson

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))
9
ahuigo

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); });
9
Ebrahim Byagowi

Si vous utilisez déjà jQuery, je recommanderais tinysort: http://tinysort.sjeiti.com/

$("li").tsort({order:"asc"});
$("li").tsort({order:"desc"});
8
Jay

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;
  }
});
5
cgenco

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; });
1
peter