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

    Дерево помнит выбранный узел по 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 — я сомневаюсь.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 18
    • 0
      уберите подчёркивание ссылок
    • +2
      Извините, я нагло воспользуюсь вашей темой чтобы явить миру дерево деталей, над котором я работал последние 2 часа ( homm.stratero.ru/pages/globalres-catalog/ ) и грязно выругаться на вонючий тупой эксплорер всех версий! Почему огромная корпорация не может сделать нормальный браузер, а вот уже 10 лет лепит говно тормозящее? Что, 10 и 4 дива предел для супер-браузера? Почему скроллинг тормозит? Что сказать посетителям будущего сайта? Извините, мол ваш браузер — говно? Это конечно будет правда, но так тоже нельзя.
      Любители священного в последнее время ИЕ могут минусовать.
      • 0
        Вам нравится, когда пользователи вынуждены целиться в малюсенькие треугольнички?
        • 0
          Это как-бе не относится к теме, но я отвечу: мне не нравится, когда пользователи вынуждены целиться в малюсенькие треугольнички, именно по этой причине там малюсенькие треугольнички на картинке с относительно большими падингами, в которую можно сильно не целится.
          • 0
            Не очень интуитивно тогда получается — вроде при наведении раздел подсвечивается, но при клике ничего не происходит: ни раскрытия дерева, ни перехода по ссылке, ни подгрузки контента (с раскрытием дерева).
            • 0
              > ни перехода по ссылке, ни подгрузки контента
              Это называется «пример верстки, выложенный для ознакомления с убогостью ИЕ». Там, естественно, ничего еще не работает.
        • 0
          UPD: Пришел на работу, здесь в разы более слабый процессор и в десятки раз более слабая видеокарта. Приведенный мной пример просто летает! Не понятно, что делать, радобаваться, или злиться еще сильнее.
          • 0
            Сталкивался, нужно оптимизировать код на jquery. В моем случае было больше 100 окошек с чатами на 1 странице (сворачивались разворачивались как у вас), тормозило. Начали оптимизировать, стало лучше то всеравно не то. Попробовали плагин accordion и все заработало шустрее не бывает. Однако он вам врядли подойдет, там по принципу что-то открылось, остальное закрылось.
          • 0
            А добавьте пример хоть одну рабочую ссылку дерева?

            По поводу сохранения состояния дерева — Вы можете по клику или по onUnload записать состояние дерева в куку, а на следующей странице его прочитать. Не знаю, насколько это best practice, но работать будет.
            • 0
              Внизу статьи ссылка на рабочий пример. Возможно хостинг тупит — попробуйте обновить страницу пару раз.

              Про куку, я в конце статьи написал, примерно тоже самое.
              Винматэльнэе будь! © Гарик Мартиросян
              • 0
                >> А добавьте пример хоть одну рабочую ссылку дерева?
                > Внизу статьи ссылка на рабочий пример. Возможно хостинг тупит — попробуйте обновить страницу пару раз.

                Упс, там должно было быть написано «добавьте В пример». Чтобы хоть одна ссылка в дереве вела на обновление страницы.

                А про куку, проморгал :-/ Чёрт, давно говорю себе: «иди спать, иди спать, иди спать...» :)
                • 0
                  Ладно сделаю такой пример, как домой приду
            • 0
              Может быть я буду не прав, но стоит в конце обработчика click вписать return false; дабы в адресной строке не появлялись строки типа #номер_узла.

              А так, просто прекрасно r3code, вы молодец.
              • 0
                Это ссылки у меня там так прописаны, чтобы было индивидуально для каждой ставил href="#номер_узла"
                Для примера сделал адреса с якорями, чтобы не плодить 10 тестовых страниц.

                Что изменит может return false посмотрю, но кажется мне ничего не измениться особенно.
                • 0
                  только лучше не return: false, а event.preventDefault()
              • 0
                Все отлично.
                Вот вам еще материал для размышлений habrahabr.ru/blogs/webdev/30302/
                • 0
                  Перенесите в Веб-разработку

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.