Русские документы
Ежедневные компьютерные новости RSS rusdoc.ru  Найти :
Новости
Последние поступления
Книжный магазин
  Hardware:
Видеоустройства
Системные платы
Процессоры
Мобильные устройства
Аудиосистема
Охлаждение системы
Накопители информации
КПК и ноутбуки
Телефоны и связь
Периферия
Система
Сети
Разные устройства
 
  Programming:
Web-разработка
Языки программирования
Технологии и теория
Разработка игр
Программная инженерия
 
  Software:
Операционные системы
Windows 7
Базы данных
Обзоры программ
Графика и дизайн
   
  Life:
Компьютерная жизнь
Разные материалы
   
Партнеры
Публикация
Правовая информация
Реклама на сайте
Обратная связь
Экспорт в RSS Экспорт в RSS2.0
    Читать в Яндекс.Ленте



Многоуровневое дерево с маркерами, сохраняющее состояние (HTML, CSS, jQuery, Cookies)

Раздел: Programming / Вебмастеру @ 20.05.2009 | Ключевые слова: html верстка дерево маркер версия для печати

Источник: habrahabr

Продолжается развитие темы о многоуровневом дереве с маркерами. Многоуровневое дерево с сохранением состояния узлов
Теперь дерево выросло и окрепло, стало взрослее и помнит выбранный узел и состояние кажого узла в отдельности.
Страницу можно перезагружать, а дерево все равно будет помнить все что вы открыли и выбрали!


Для сохранания состояния использованы Cookies и jquery.cookies.js плагин. Работать с cookies очень просто.

Подготовка Html


Дерево будет работать, если выполнить базовое условие — оформить html в таком виде:
<div id="multi-derevo">
  <h4><a href="#">Заголовок</a></h4>
  <ul>
   <li><span><a href="#1">1. Ветка</a></span>
     <ul>
      <li><span><a href="#11">1.1. Ветка</a></span>
        <ul>
         <li><span><a href="#111">1.1.1. Листик</a></span></li>
         <li><span><a href="#112">1.1.2. Цветок </a></span></li>
         <li><span><a href="#113">1.1.3. Цветок </a></span></li>
        </ul>
      </li>
     </ul>
   </li>
   <li><span><a href="#2">2. Ветка</a></span></li>
  </ul>
</div><!-- /multi-derevo -->


Для сосздания подуровня достатночно вставить после заголовка узла вложенный список такой же структуры.

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

Обновленный скрипт дерева


Все пояснения в комментариях кода.
/*
© 2009 r3code.habrahabr.ru
По вопросам модификации под задачу обращайтесь

Скрипт: Построение дерева по готовому HTML списку.
r3code.habrahabr.ru/blog/59823/

Выделяем узлы имющие поддеревья и добавляем у ним метку.
Определяет поведение узлов дерева при клике на них.
 - Изменяет состояние маркера раскрытия (открыт/закрыт).
 - Узлы содержащие в себе другие узлы, по клику разворачиваются
  или сворачиваются, в зависимости от текущего состояния.
 - При переходе с одного узла на другой снимается выделение (.current)
  и пеходит на выбранный узел.
 - Определяет последний узел с поддеревом и скрывает соединительную
  линию до следующего узла этого уровня.
 - Сохранаяет состояние узлов (откр./закр.) и выбранный узел в cookies.
 - При установленных cookies состояние узлов восстанавливается при загрузке.

 19/05/2009
*/
//=================================================================================

$(document).ready(function () {
/* Расставляем маркеры на узлах, имющих внутри себя поддерево.
  Выбираем элементы `li` которые имеют вложенные `ul`, ставим для них
  маркер, т.е. находим в этом `li` вложенный тег `a`
  и в него дописываем маркер `<em class="marker"></em>`.
  a:first используется, чтобы узлам ниже 1го уровня вложенности
  маркеры не добавлялись повторно.
*/
var root = $(`#multi-derevo`);
// уникальные идентификаторы всем узлам, сквозная нумерация (Nested set)
$(`li`, root).each(function (index) {
  this.id = `n` + index;
});
$(`li:has("ul")`, root).find(`a:first`).prepend(`<em class="marker"></em>`);

// выбрать текущий узел
var current_id = $.cookie(`current_node`);
if(current_id) $(`#`+current_id).find(`a:first`).toggleClass(`current`);

// вешаем событие на клик по ссылке
//-----------------------------------
$(`li span`, root).click(function () {
  // снимаем выделение предыдущего узла
  $(`a.current`, root).removeClass(`current`);
  var a = $(`a:first`,this.parentNode);
  a.toggleClass(`current`);
  var current_id = a.parent(`li`).attr(`id`);
  //alert(a.parents(`li`).get(0).tagName+"#"+a.parents(`li`).attr(`id`));
  setCookie(`current_node`,a.parents(`li`).attr(`id`) || null);
  // Выделяем выбранный узел
  toggleNode(this.parentNode);
});
//postLoad(); // функция раскрытия по текущему url
openNodes(); // открыть по данным cookie
})

//---------------------------------------------------------------------------------
// Выделил функцию разворачивания дерева в отдельную  
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`);
  saveTreeState();
}  
}

// функция обработки последнего узла в уровне
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`); 
}
}

// подготовка информации о сосотояниях узлов
function GetOpenedNodes(items){ // li:has(`ul`)
 var str = [];
 $(items).each(function() {
  var res = $(this).attr(`id`);
  var state = $(`em:first`,this).hasClass(`open`) ? 1 : ``;
  if(res && state){
   str.push(res);
  }
 });
 return str.join(`,`);
}

// сохранить полный список открытых узлов
function saveTreeState(){
 var open_id = GetOpenedNodes($(`#multi-derevo li:has("ul")`)) || null;
 setCookie("open_nodes", open_id);
 return false;
}

// раскрытие узлов по указанному списку
function openNodes(){
  // читаем куки и открываем узлы
 var open_nodes = $.cookie("open_nodes");
  if(open_nodes) {
  var nodes = open_nodes.split(`,`);
  
  if(nodes[0]){
   for(var node in nodes){
    nodes[node] = `#` + nodes[node]; 
   }
   var ids = nodes.join(`,`);
   $(ids).each(function() {
     toggleNode($(this));
   });
  }
 }
 return false;
}

// настройки хранить в Cookies 1 день
function setCookie(name, value){
 var DAY = 24 * 60 * 60 * 1000;
 var date = new Date();
 date.setTime(date.getTime() + (1 * DAY)); // 1 день
 $.cookie(name, value, {expires: date});
 // alert("Cookie set: "+name+"="+value);
}



Мне конечно хотелось бы сделать рефакторинг кода с учетом возможностей jQuery, этот вариант написан так как я знаю. не откажусть от полезных мыслей по улучшению вида этого кода.

Скрипт в работе


Посмотреть работающий пример.

UPD 19.05.2009
Отказался от сохранения состояния дерева при unload — Opera не поддерживает. Теперь состояние дерева сохраняется при клике на узел. Пример и скрипт обновлен.

Это интересно:








версия для печатиРаспечатать статью


Вернуться в раздел: Programming / Вебмастеру


Реклама:
Читать наc на:

Add to Google
Читать в Яндекс.Ленте






Rambler's Top100
© Copyright 1998-2012 Александр Томов. All rights reserved.