Как стать автором
Обновить

Многоуровневое дерево с маркерами (HTML, CSS, jQuery). Запоминаем выбранный узел

Время на прочтение5 мин
Количество просмотров6.3K
Дерево помнит выбранный узел по urlЭто продолжение темы про дерево. Хочу его довести до ранга «готов к внедрению». Потому повозился с JavaScript и сделал запоминание выбранного узла на основе адреса ссылки.
Если ссылка вложена в поддерево, дерево развернется до её уровня и, если у неё самой есть поддерево — оно тоже будет развернуто.

JavaScript сделал как смог, т.к. давно не использовал. Прошу помощи в доработке и оптимизации.


В этой версии не менялся HTML и CSS, если хотите — посмотрите его в предыдущей статье.

Следущая статья продолжение — дерево с сохраненим состояния узлов.

JavaScript

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
  <script>
  /*<![CDATA[*/
   /*
     Построение дерева по готовому HTML списку.
  
     Выделяем узлы имющие поддеревья и добавляем у ним метку.
     Функция определяет поведение узлов дерева при клике на них.
   - Изменяет состояние маркера раскрытия (открыт/закрыт).
     - Узлы содержащие в себе другие узлы, по клику разворачиваются
      или сворачиваются, в зависимости от текущего состояния.
     - При переходе с одного узла на другой снимается выделение (.current)
      и пеходит на выбранный узел.
     - Определяет последний узел с поддеревом и скрывает соединительную
      линию до следующего узла этого уровня.
   */
   $(document).ready(function () {
   /* Расставляем маркеры на узлах, имющих внутри себя поддерево.
      Выбираем элементы 'li' которые имеют вложенные 'ul', ставим для них
      маркер, т.е. находим в этом 'li' вложенный тег 'a'
      и в него дописываем маркер '<em class="marker"></em>'.
      a:first используется, чтобы узлам ниже 1го уровня вложенности
      маркеры не добавлялись повторно.
   */
     $('#multi-derevo li:has("ul")').find('a:first').prepend('<em class="marker"></em>');
   // вешаем событие на клик по ссылке
     $('#multi-derevo li span').click(function () {
      // снимаем выделение предыдущего узла
      $('a.current').removeClass('current');
      var a = $('a:first',this.parentNode);
      // Выделяем выбранный узел
      //было a.hasClass('current')?a.removeClass('current'):a.addClass('current');
       a.toggleClass('current');
      toggleNode(this.parentNode);
      
     });
     postLoad();
   })
   // Выделил функцию разворачивания дерева в отдельную  
   function toggleNode(Node) {// node= li
     prepareLast(Node);
     // анимация раскрытия узла и изменение состояния маркера
     var ul=$('ul:first',Node);// Находим поддерево
     if (ul.length) {// поддерево есть
      ul.slideToggle(200); //свернуть или развернуть
      // Меняем сосотояние маркера на закрыто/открыто
      var em=$('em:first',Node);// this = 'li span'
      // было em.hasClass('open')?em.removeClass('open'):em.addClass('open');
      em.toggleClass('open');
     }  
   }
   // функция обработки последнего узла в уровне
   function prepareLast(Node) {
     /* если это последний узел уровня, то соединительную линию к следующему
     рисовать не нужно */  
     $(Node).each(function(){
      if (!$(this).next().length) {
        /* берем корень разветвления <li>, в нем находим поддерево <ul>,
         выбираем прямых потомков ul > li, назначаем им класс 'last' */
        $(this).find('ul:first > li').addClass('last');
      } 
     })
   }
   // функция разворачивания дерева до выбранной ранее ссылки
   function postLoad(){
     var url = window.location.toString();
     var max = 0;
     var a = null;
     $('#multi-derevo li span a').each(function(){
      // сравниваем адрес страницы и ссылку из атрибута
      if(url.indexOf(this.href) >= 0 && this.href.length > max){
        a = this;
        max = this.href.length;
      }
     });
     // если узел не виден, то разворачиваем дерево
     if ($(a).is(':hidden') || $(a).parents(':hidden').length) {
      var li = $(a).parents().filter('li');
      prepareLast(li);
      toggleNode(li);
     }
     // выделим выбранный узел
     if (a) {
      $(a).toggleClass('current');
     }
     else { // первый показ, выберем первую ссылку (можно убрать если не нужно)
      $('#multi-derevo li span a:first').toggleClass('current'); 
     }
   }
  /*]]>*/
  </script>


Почему-то для первого уровня не получилось сделать авто раскрытие поддерева после загрузки, если узел был выбран ранее.
Нуждается в доработке, с охотой приму все улучшения.

У этого примера есть недостаток в том, что не запоминается состояние всех узлов, а только положение выбранного.
Т.е. ранее дерево было развернуто на 3 уровня в глубь, то после перехода по ссылке с самого верха развернется только первый подуровень.

Посмотрите пример.

Еще хочу сделать модификацию с cookies, которая будет запоминать все развернутые поддеревья, т.е. если ранее пользователь развернул дерево и потом свернул верхний уровень, то про разворачивании вложенное дерево будет также развернуто. И конечно все состояние благодаря cookies будут сохраняться при переходе между страницами.

ХабраНарод скажите подходит по тематике этот топика в этот блок или все ж перенести в Web-разработку или в jQuery — я сомневаюсь.
Теги:
Хабы:
Всего голосов 22: ↑18 и ↓4+14
Комментарии18

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань