How do I sort a multi-level list in alphabetical order?

I need to sort the list at each level, which I did below, but the problem is that the DOM tree remains the same, which is completely unacceptable, because after sorting alphabetically, the sublists lose their connection with the item above the level. How to implement all this correctly? I would be very grateful.

  let abc = document.createElement('div');
        abc.id = 'abc';
        document.body.appendChild(abc, document.body.lastChild);
    
        let firstLevelLis = document.querySelectorAll('body > ul > li');
    
        let vals1 = [];
    
        for(let i = 0, l = firstLevelLis.length; i < l; i++) {
            vals1.push(firstLevelLis[i].innerHTML);
        };
    
        vals1.sort();
    
        for(let i = 0, l = firstLevelLis.length; i < l; i++) {
            firstLevelLis[i].innerHTML = vals1[i];
        }
    
        let secondLevelLis = document.querySelectorAll('body > ul > ul > li');
    
        let vals2 = [];
    
        for(let i = 0, l = secondLevelLis.length; i < l; i++) {
            vals2.push(secondLevelLis[i].innerHTML);
        };
    
        vals2.sort();
    
        for(let i = 0, l = secondLevelLis.length; i < l; i++) {
            secondLevelLis[i].innerHTML = vals2[i];
        }
    
        let thirdLevelLis = document.querySelectorAll('body > ul > ul > ul > li');
    
        let vals3 = [];
    
        for(let i = 0, l = thirdLevelLis.length; i < l; i++) {
            vals3.push(thirdLevelLis[i].innerHTML);
        };
    
        vals3.sort();
    
        for(let i = 0, l = thirdLevelLis.length; i < l; i++) {
            thirdLevelLis[i].innerHTML = vals3[i];
        }
    
<!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html" charset="utf-8">
    </head>
    <body>
        <ul>
            <li>Введение в JavaScript</li>
            <ul>
                <li>Размещение скриптов на HTML-страницах</li>
                <li>Синтаксис языка</li>
                <li>Типы данных</li>
                <ul>
                    <li>Объект Global</li>
                    <li>Оборачивание (wrapping), изменчивость (mutability)</li>
                    <li>Преобразование типов, основные методы: toString, valueOf</li>
                    <li>Инициализация объектов, массивов и функций</li>
                </ul>
                <li>Переменные и область видимости</li>
                <li>Операторы языка</li>
                <li>Выражения: условия и циклы</li>
                <li>Операторы перехода (label, break, continue, return)</li>
                <li>Исключения и обработка ошибок: try/catch/finally, throw</li>
            </ul>
            <li>Работа с объектами в JavaScript</li>
            <ul>
                <li>Создание объектов</li>
                <li>Доступ к свойствам: опрос, добавление, удаление и перечисление свойств</li>
                <li>Массивы, методы работы с массивами</li>
                <li>Функции и передача параметров</li>
            </ul>
            <li>JavaScript в браузере</li>
            <ul>
                <li>Очередность выполнения скриптов</li>
                <li>DOM: объектная модель документа</li>
                <ul>
                    <li>Основные объекты браузера, объект Window</li>
                    <li>Объект Document: поиск и работа с элементами</li>
                    <li>Настройка и изменение стилей документа</li>
                    <li>Обработка событий</li>
                    <li>Графика: элемент canvas</li>
                </ul>
                <li>Работа с формами: валидация данных, регулярные выражения</li>
            </ul>
        </ul>
    </body>
    
      
    </html>
Author: Leks, 2019-11-21

1 answers

I changed the markup a little: The adjacent ul c li created additional difficulties... where there should be a ul under li-I inserted this ul inside (if desired, you can add a small script that will perform this change itself).

let ul = document.querySelectorAll('ul'); // Получаю только ul вместо ul > li

for (let i = 0; i < ul.length; i++) {
  // Уже внутри, для каждого ul можно рассматривать его дочерние li.
  let li = [...ul[i].children].sort((a, b) => {
    return a.textContent >= b.textContent ? 1 : -1
  });
  /* ul[i].children возвращает список элементов, но это не обычный массив, у него нет
  метода sort(). Оператор ... позволяет добавлять элементы из списка в массив,
  и сортировать уже его 

  Если хочется поддерживать старые браузеры - можно собрать тот же массив
  через цикл. А с кодом ниже - также, appendChild через цикл. */

  ul[i].append( ...li ); // (*1) 
  /* Тот же оператор ... позволяет сразу передать в качестве аргументов функции 
  все элементы массива. Как-бы через запятые append( li[0], li[1], li[2])*/
}
<ul>
  <li>Введение в JavaScript
    <ul>
      <li>Размещение скриптов на HTML-страницах</li>
      <li>Синтаксис языка</li>
      <li>Типы данных
        <ul>
          <li>Объект Global</li>
          <li>Оборачивание (wrapping), изменчивость (mutability)</li>
          <li>Преобразование типов, основные методы: toString, valueOf</li>
          <li>Инициализация объектов, массивов и функций</li>
        </ul>
      </li>

      <li>Переменные и область видимости</li>
      <li>Операторы языка</li>
      <li>Выражения: условия и циклы</li>
      <li>Операторы перехода (label, break, continue, return)</li>
      <li>Исключения и обработка ошибок: try/catch/finally, throw</li>
    </ul>
  </li>

  <li>Работа с объектами в JavaScript
    <ul>
      <li>Создание объектов</li>
      <li>Доступ к свойствам: опрос, добавление, удаление и перечисление свойств</li>
      <li>Массивы, методы работы с массивами</li>
      <li>Функции и передача параметров</li>
    </ul>
  </li>

  <li>JavaScript в браузере
    <ul>
      <li>Очередность выполнения скриптов</li>
      <li>DOM: объектная модель документа
        <ul>
          <li>Основные объекты браузера, объект Window</li>
          <li>Объект Document: поиск и работа с элементами</li>
          <li>Настройка и изменение стилей документа</li>
          <li>Обработка событий</li>
          <li>Графика: элемент canvas</li>
        </ul>
      </li>
      <li>Работа с формами: валидация данных, регулярные выражения</li>
    </ul>
  </li>
</ul>

(*1) - if an existing element on the page is tried to be inserted somewhere else, it is not copied - it is simply transferred. Therefore, all the elements of the list are re-arranged in the desired order.

 1
Author: OPTIMUS PRIME, 2019-11-21 23:09:21