Самый простой способ отсортировать узлы DOM?

Если у меня есть такой список:

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

Какой самый простой способ переупорядочить узлы DOM в соответствии с моими предпочтениями? (Это должно происходить автоматически, когда страница загружается, предпочтение порядка списка берется из файла cookie)

Например.

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

Я не уверен, что это поможет вам, но если вы используете серверную технологию (например, PHP) на этой странице, то она также должна иметь доступ к файлам cookie. в PHP - в глобальном массиве $ _COOKIE.

nickf 12.11.2008 04:05
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
66
1
54 841
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Ответ принят как подходящий

Хотя, вероятно, есть более простой способ сделать это с помощью библиотеки JS, вот рабочее решение с использованием 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]);
}

Спасибо за ваше решение, NickF, я собираюсь немного его адаптировать, поскольку я использую jQuery, но я думаю, что теперь у меня есть идея, как это сделать, спасибо! :)

James 12.11.2008 04:56

Используя list.children вместо list.childNodes, вы можете избежать проверки текстовых узлов.

Livingston Samuel 27.04.2010 19:26

Когда я впервые прочитал этот ответ, я подумал, что vanilla js? Почему здесь требуется vanilla.js? : ^)

zipzit 16.11.2017 20:59

@LivingstonSamuel ... но за счет того, что он не работает в IE (даже IE11!)

leo 26.09.2018 16:52

Вы можете обнаружить, что сортировка узлов DOM не работает. Другой подход состоял бы в том, чтобы иметь в вашем javascript массив, представляющий данные, которые будут поступать в узлы DOM, отсортировать эти данные, а затем повторно создать div, содержащий узлы DOM.

Может быть, у вас не так много узлов для сортировки, поэтому это не имеет значения. Мой опыт основан на попытке отсортировать HTML-таблицы, манипулируя DOM, включая таблицы с сотнями строк и парой десятков столбцов.

Если вы уже используете jQuery, я бы порекомендовал tinysort: http://tinysort.sjeiti.com/

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

Tinysort в несколько раз медленнее, чем 13 строк кода, на основе сортировки результата выбора jquery и его повторного добавления - jsperf.com/attr-vs-getattribute/12

mas.morozov 05.10.2014 02:26

TinySort раньше был плагином jQuery, но был переписан, чтобы удалить зависимость jQuery. Теперь он меньше и быстрее

Giacomo Tecya Pigani 24.04.2017 21:22

не анализируя слишком много, если это приносит что-то новое в таблицу, я обычно использую это:

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

где элемент - это массив потомков одного и того же родителя. мы удаляем начало с последнего и добавляем, начиная с первого, чтобы избежать мерцания в верхней части, которая, вероятно, находится на экране. Я обычно получаю свой массив элементов следующим образом:

forEachSnapshot(document.evaluate(..., 6, null), function(n, i){ items[i] = n; });

Посмотреть в действии: 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);
            });
        };
    })();

Лаконичный

Хороший! Мне также нравится лаконичность, поэтому на основе этого я придумал очень простая функция jQuery, который позволяет вам предоставить функцию обратного вызова, которая вычисляет значение для сортировки. (Я включил два примера: сортировка списка по алфавиту и сортировка таблицы по числовому значению в первом столбце - оба, по сути, однострочные.)

mindplay.dk 04.10.2013 01:30

Я знаю, что это старый пост, но могу ли я спросить, в чем преимущество использования самоисполняющейся функции, возвращающей функцию sortDomElements? Не было бы проще сказать jQuery.fn.sortDomElements = function (сравнитель) ...? вот так jsfiddle.net/y7JyT/77

Julian 03.08.2016 02:56

Моя версия, надеюсь будет полезна другим:

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

Что значит /* sort logic */? : / Код выглядит неплохо, но моя логика сортировки слабовата

Arthur Tarasov 16.07.2017 13:42

Это означает, что вы должны поместить туда свою логику сортировки, взглянуть на developer.mozilla.org/en/docs/Web/JavaScript/Reference/…, в основном это то же самое, только x и y являются узлами DOM.

Ebrahim Byagowi 16.07.2017 14:06

Вот функция ES6 для сортировки узлов DOM на месте:

const sortChildren = ({ container, childSelector, getScore }) => {
  const items = [...container.querySelectorAll(childSelector)];

  items
    .sort((a, b) => getScore(b) - getScore(a))
    .forEach(item => container.appendChild(item));
};

Вот как вы могли бы использовать его для сортировки Неизвестные отзывы пользователей по баллам:

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

Используйте синтаксис es6 для обращения к детям:

var list = document.querySelector('#test-list');

[...list.children]
  .sort((a,b)=>a.innerText>b.innerText?1:-1)
  .forEach(node=>list.appendChild(node));

хороший! это чистый способ сделать это.

wasddd_ 20.06.2018 10:12

Блестяще! Самый умный способ изменить порядок узлов

Velojet 03.10.2019 07:42

Это лучшее решение

Samuel 08.05.2020 01:59

Семантически более корректно использовать метод «forEach» вместо «map», поскольку в этом случае вас не интересует фактическое сопоставление элементов, вы просто хотите вызвать обратный вызов с побочным эффектом (присоединение к другому элемент).

everyonesdesign 28.05.2020 15:57

Самый изящный способ, который я могу придумать:

Параметр compare аналогичен функции сравнения, используемой в Array.sort ().

Отсортируйте дочерние узлы.

/**
 * @param {!Node} parent
 * @param {function(!Node, !Node):number} compare
 */
function sortChildNodes(parent, compare) {
  const moveNode = (newParent, node) => {
    // If node is already under a parent, append() removes it from the
    // original parent before appending it to the new parent.
    newParent.append(node);
    return newParent;
  };
  parent.append(Array.from(parent.childNodes) // Shallow copies of nodes.
                    .sort(compare) // Sort the shallow copies.
                    .reduce(moveNode, document.createDocumentFragment()));
}

Отсортируйте дочерние элементы (подмножество дочерних узлов).

/**
 * @param {!Element} parent
 * @param {function(!Element, !Element):number} compare
 */
function sortChildren(parent, compare) {
  const moveElement = (newParent, element) => {
    // If element is already under a parent, append() removes it from the
    // original parent before appending it to the new parent.
    newParent.append(element);
    return newParent;
  };
  parent.append(Array.from(parent.children) // Shallow copies of elements.
                    .sort(compare) // Sort the shallow copies.
                    .reduce(moveElement, document.createDocumentFragment()));
}

Другие вопросы по теме