Pull to refresh

Генерация древовидного меню модели представления Nested Sets

Reading time 3 min
Views 19K
В процессе работы над одним из проектов передо мной встала задача создания сворачиваемого дерева папок на основе сведений о нем в базе данных. Для уточнения, это выглядит примерно так:

image

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

Мы имеем следующую структуру таблицы в БД:
id — идентификатор строки
level — уровень элемента
left_key — левый ключ
right_key — правый ключ
caption — название каталога.
Более подробно о создании такой таблицы вы можете узнать здесь.
Посредством AJAX эти данные, отсортированные по значению поля left_key, поступают на клиента, где мы должны построить на их основе вложенный список.
Список должен иметь следующую структуру:
Элемент <ul>, содержащий:
    элемент <li>, представляющий собой каталог. 
        Далее, в нем всегда есть элемент <span>, содержащий название каталога. 
        При условии наличия дочерних папок, в нем есть элемент <ul>
            и так далее...
    и так далее... 

Приступим к генерации дерева.
В первую очередь, необходимо создать функцию, возвращающую дочерние элементы или пустой массив в случае их отсутствия.
var getChilds = function(trgt, arr){
    var childs = Array();
    var length = arr.length;
    for (var i = 0; i < length; i++){
        var curr = getInts(arr[i]);
        var under = (curr.level > trgt.level) ;
        var l_in =  (curr.left_key > trgt.left_key);
        var r_in =  (curr.right_key < trgt.right_key);
        if (under && l_in && r_in) childs.push(arr[i]);
    }
    return childs;
}

Эта функция делает не что иное, как проверку каждого элемента массива по заданному элементу этого же массива, то есть: если уровень рассматриваемого элемента ниже уровня заданного элемента, при том что левые и правые ключи соответственно находятся в промежутке между левым и правым ключом заданного элемента, то записываем рассматриваемый элемент в массив дочерних элементов.
Функция getInts в данном случае занимается преобразованием значений полей level, left_key и right_key в числовые значения. Нужно это для того, чтобы происходило сравнение чисел, а не строк.
var getInts = function(arr){
    temp = Object();
    for (var i in arr){
        if (i!='name') temp[i] = parseInt(arr[i])
        else temp[i] = arr[i]
    return temp
}

После получения дочерних элементов, необходимо очистить от них исходный массив. Я не придумал ничего лучше, чем написать еще одну функцию.
var cleanDuplicates = function(from, elements){
    var length = arr.length;
    for (var i = 0; i < length; i++){
        if ($.inArray(from[i], elements) > -1)
            delete from[i]
    }
    return from;
}

Здесь массив elements содержит элементы, которые требуется удалить из массива from.
И, наконец, строим список, используя вышеприведенные функции.
var ul = function(arr){
    if (!arr[0]) return ''
    else{
        var html = '<ul>';
        var length = arr.length;
        for (var i = 0; i < length; i++){
            var el = arr[i];
            var childs = getChilds(el, arr);
            arr = cleanDuplicates(arr, childs)
            html += '<li>'+'<span id="cat_'+el.id+'">'+el.name+'</span>'
            html += ul(childs)
            html += '</li>'
        }
        return html + '</ul>'
    }
}

Пример использования:
'<div class="tree">' + ul(data) + '</div>'

где data — данные, полученные с сервера.
Для конечного преобразования этого списка в древовидное меню существует достаточно большое количество плагинов для jQuery, к примеру jQuery Treeview.
Работа с ним достаточно проста. Необходимо сперва подключить сам jQuery, затем этот плагин. После подключения достаточно просто натравить его на блок, содержащий ваш сгенерированный список. Если брать из примера, то это элемент $('.tree').
$('.tree').treeview();

В результате мы имеем древовидное меню, которое поддерживает сворачивание/разворачивание по клику на папке (по умолчанию строится развернутое дерево папок, но благодаря настройкам плагина возможны варианты, подробнее читайте здесь).

P. S. Обратите внимание, что плагин jQuery Treeview больше не развивается, но для построения простого древовидного меню функций этого плагина более чем достаточно. Сам разработчик предлагает использовать плагин JqTree.
Tags:
Hubs:
+2
Comments 23
Comments Comments 23

Articles